@cleocode/caamp 1.1.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-7YV3KXEJ.js → chunk-O2YG5HT7.js} +250 -47
- package/dist/chunk-O2YG5HT7.js.map +1 -0
- package/dist/cli.js +768 -261
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +48 -6
- package/dist/index.js +17 -1
- package/package.json +1 -1
- package/dist/chunk-7YV3KXEJ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
MarketplaceClient,
|
|
5
5
|
RECOMMENDATION_ERROR_CODES,
|
|
6
6
|
applyMcpInstallWithPolicy,
|
|
7
|
+
buildCleoProfile,
|
|
7
8
|
buildServerConfig,
|
|
8
9
|
buildSkillSubPathCandidates,
|
|
9
10
|
checkAllInjections,
|
|
11
|
+
checkCommandReachability,
|
|
10
12
|
checkSkillUpdate,
|
|
11
13
|
configureProviderGlobalAndProject,
|
|
12
14
|
detectAllProviders,
|
|
@@ -40,6 +42,8 @@ import {
|
|
|
40
42
|
listMcpServers,
|
|
41
43
|
listProfiles,
|
|
42
44
|
listSkills,
|
|
45
|
+
normalizeCleoChannel,
|
|
46
|
+
parseEnvAssignments,
|
|
43
47
|
parseSource,
|
|
44
48
|
readConfig,
|
|
45
49
|
readLockFile,
|
|
@@ -50,6 +54,8 @@ import {
|
|
|
50
54
|
removeMcpServer,
|
|
51
55
|
removeSkill,
|
|
52
56
|
removeSkillFromLock,
|
|
57
|
+
resolveChannelFromServerName,
|
|
58
|
+
resolveCleoServerName,
|
|
53
59
|
resolveConfigPath,
|
|
54
60
|
resolvePreferredConfigScope,
|
|
55
61
|
resolveProfile,
|
|
@@ -65,7 +71,7 @@ import {
|
|
|
65
71
|
tokenizeCriteriaValue,
|
|
66
72
|
updateInstructionsSingleOperation,
|
|
67
73
|
validateSkill
|
|
68
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-O2YG5HT7.js";
|
|
69
75
|
|
|
70
76
|
// src/cli.ts
|
|
71
77
|
import { Command } from "commander";
|
|
@@ -1601,10 +1607,559 @@ function registerInstructionsCommands(program2) {
|
|
|
1601
1607
|
registerInstructionsUpdate(instructions);
|
|
1602
1608
|
}
|
|
1603
1609
|
|
|
1604
|
-
// src/commands/mcp/
|
|
1610
|
+
// src/commands/mcp/cleo.ts
|
|
1611
|
+
import { createInterface } from "readline/promises";
|
|
1605
1612
|
import pc6 from "picocolors";
|
|
1613
|
+
function collect(value, previous) {
|
|
1614
|
+
return [...previous, value];
|
|
1615
|
+
}
|
|
1616
|
+
function collectTargetProviders(providerIds, all) {
|
|
1617
|
+
if (all) {
|
|
1618
|
+
return getInstalledProviders();
|
|
1619
|
+
}
|
|
1620
|
+
if (providerIds.length > 0) {
|
|
1621
|
+
return providerIds.map((id) => getProvider(id)).filter((provider) => provider !== void 0);
|
|
1622
|
+
}
|
|
1623
|
+
return getInstalledProviders();
|
|
1624
|
+
}
|
|
1625
|
+
async function validateProfile(provider, scope, serverName) {
|
|
1626
|
+
const entries = await listMcpServers(provider, scope);
|
|
1627
|
+
const entry = entries.find((candidate) => candidate.name === serverName);
|
|
1628
|
+
if (!entry) {
|
|
1629
|
+
return { valid: false, reason: "server missing after write" };
|
|
1630
|
+
}
|
|
1631
|
+
const command = typeof entry.config.command === "string" ? entry.config.command : void 0;
|
|
1632
|
+
if (!command) {
|
|
1633
|
+
return { valid: true };
|
|
1634
|
+
}
|
|
1635
|
+
const reachability = checkCommandReachability(command);
|
|
1636
|
+
if (!reachability.reachable) {
|
|
1637
|
+
return {
|
|
1638
|
+
valid: false,
|
|
1639
|
+
reason: `command not reachable (${reachability.method}: ${reachability.detail})`
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
return { valid: true };
|
|
1643
|
+
}
|
|
1644
|
+
async function detectServerConflicts(providers, scope, targetServerName) {
|
|
1645
|
+
const warnings = [];
|
|
1646
|
+
for (const provider of providers) {
|
|
1647
|
+
const entries = await listMcpServers(provider, scope);
|
|
1648
|
+
const existing = entries.find((entry) => entry.name === targetServerName);
|
|
1649
|
+
if (!existing) continue;
|
|
1650
|
+
const command = typeof existing.config.command === "string" ? existing.config.command : "";
|
|
1651
|
+
const args = Array.isArray(existing.config.args) ? existing.config.args.filter((value) => typeof value === "string") : [];
|
|
1652
|
+
const flat = `${command} ${args.join(" ")}`.toLowerCase();
|
|
1653
|
+
if (!flat.includes("cleo")) {
|
|
1654
|
+
warnings.push({
|
|
1655
|
+
providerId: provider.id,
|
|
1656
|
+
message: `Server name '${targetServerName}' already exists with a non-CLEO command in ${provider.id}.`
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return warnings;
|
|
1661
|
+
}
|
|
1662
|
+
function formatInstallResultHuman(mode, channel, serverName, scope, results, validations) {
|
|
1663
|
+
console.log(pc6.bold(`${mode === "install" ? "Install" : "Update"} CLEO channel: ${channel}`));
|
|
1664
|
+
console.log(pc6.dim(`Server: ${serverName} Scope: ${scope}`));
|
|
1665
|
+
console.log();
|
|
1666
|
+
for (const result of results) {
|
|
1667
|
+
const validation = validations.find((entry) => entry.providerId === result.provider.id);
|
|
1668
|
+
if (result.success) {
|
|
1669
|
+
const validationLabel = validation?.valid ? pc6.green("validated") : pc6.yellow(`validation warning: ${validation?.reason ?? "unknown"}`);
|
|
1670
|
+
console.log(` ${pc6.green("+")} ${result.provider.toolName.padEnd(22)} ${pc6.dim(result.configPath)} ${validationLabel}`);
|
|
1671
|
+
} else {
|
|
1672
|
+
console.log(` ${pc6.red("x")} ${result.provider.toolName.padEnd(22)} ${pc6.red(result.error ?? "failed")}`);
|
|
1673
|
+
console.log(pc6.dim(" Recovery: verify config path permissions and retry with --dry-run."));
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
console.log();
|
|
1677
|
+
}
|
|
1678
|
+
async function runInteractiveInstall(opts) {
|
|
1679
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1680
|
+
try {
|
|
1681
|
+
const discovered = getInstalledProviders();
|
|
1682
|
+
if (discovered.length === 0) {
|
|
1683
|
+
throw new Error("No installed providers were detected for interactive setup.");
|
|
1684
|
+
}
|
|
1685
|
+
console.log(pc6.bold("CLEO MCP Setup"));
|
|
1686
|
+
console.log(pc6.dim("Step 1/6 - Select provider(s)"));
|
|
1687
|
+
for (const [index, provider] of discovered.entries()) {
|
|
1688
|
+
console.log(` ${index + 1}. ${provider.id} (${provider.toolName})`);
|
|
1689
|
+
}
|
|
1690
|
+
const providerAnswer = await rl.question(pc6.dim("Choose providers (e.g. 1,2 or all): "));
|
|
1691
|
+
const selectedProviders = providerAnswer.trim().toLowerCase() === "all" ? discovered.map((provider) => provider.id) : providerAnswer.split(",").map((part) => Number(part.trim())).filter((value) => Number.isFinite(value) && value > 0 && value <= discovered.length).map((index) => discovered[index - 1]?.id).filter((id) => Boolean(id));
|
|
1692
|
+
if (selectedProviders.length === 0) {
|
|
1693
|
+
throw new Error("No providers selected.");
|
|
1694
|
+
}
|
|
1695
|
+
console.log();
|
|
1696
|
+
console.log(pc6.dim("Step 2/6 - Select channel"));
|
|
1697
|
+
const channelAnswer = await rl.question(pc6.dim("Channel [stable/beta/dev] (stable): "));
|
|
1698
|
+
const selectedChannel = normalizeCleoChannel(channelAnswer || "stable");
|
|
1699
|
+
let command = opts.command;
|
|
1700
|
+
let args = [...opts.arg];
|
|
1701
|
+
let env = [...opts.env];
|
|
1702
|
+
let cleoDir = opts.cleoDir;
|
|
1703
|
+
if (selectedChannel === "dev") {
|
|
1704
|
+
command = await rl.question(pc6.dim("Dev command (required): "));
|
|
1705
|
+
const argsAnswer = await rl.question(pc6.dim("Dev args (space-separated, optional): "));
|
|
1706
|
+
args = argsAnswer.trim() === "" ? [] : argsAnswer.trim().split(/\s+/);
|
|
1707
|
+
const dirAnswer = await rl.question(pc6.dim("CLEO_DIR (~/.cleo-dev default): "));
|
|
1708
|
+
cleoDir = dirAnswer.trim() === "" ? "~/.cleo-dev" : dirAnswer.trim();
|
|
1709
|
+
if (cleoDir.trim() !== "") {
|
|
1710
|
+
env = [
|
|
1711
|
+
...env.filter((entry) => !entry.startsWith("CLEO_DIR=")),
|
|
1712
|
+
`CLEO_DIR=${cleoDir}`
|
|
1713
|
+
];
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
const profile = buildCleoProfile({
|
|
1717
|
+
channel: selectedChannel,
|
|
1718
|
+
version: opts.version,
|
|
1719
|
+
command,
|
|
1720
|
+
args,
|
|
1721
|
+
env: parseEnvAssignments(env),
|
|
1722
|
+
cleoDir
|
|
1723
|
+
});
|
|
1724
|
+
console.log();
|
|
1725
|
+
console.log(pc6.dim("Step 3/6 - Preview profile diff"));
|
|
1726
|
+
console.log(` Server: ${pc6.bold(profile.serverName)}`);
|
|
1727
|
+
console.log(` Channel: ${selectedChannel}`);
|
|
1728
|
+
console.log(` Config: ${JSON.stringify(profile.config)}`);
|
|
1729
|
+
console.log();
|
|
1730
|
+
console.log(pc6.dim("Step 4/6 - Confirm apply"));
|
|
1731
|
+
const confirm = await rl.question(pc6.dim("Apply this configuration? [y/N] "));
|
|
1732
|
+
if (!["y", "yes"].includes(confirm.trim().toLowerCase())) {
|
|
1733
|
+
throw new Error("Cancelled by user.");
|
|
1734
|
+
}
|
|
1735
|
+
return {
|
|
1736
|
+
...opts,
|
|
1737
|
+
provider: selectedProviders,
|
|
1738
|
+
channel: selectedChannel,
|
|
1739
|
+
command,
|
|
1740
|
+
arg: args,
|
|
1741
|
+
env,
|
|
1742
|
+
cleoDir,
|
|
1743
|
+
yes: true
|
|
1744
|
+
};
|
|
1745
|
+
} finally {
|
|
1746
|
+
rl.close();
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
async function executeCleoInstall(mode, opts, operation) {
|
|
1750
|
+
const mvi = "standard";
|
|
1751
|
+
let format;
|
|
1752
|
+
try {
|
|
1753
|
+
format = resolveFormat({
|
|
1754
|
+
jsonFlag: opts.json ?? false,
|
|
1755
|
+
humanFlag: (opts.human ?? false) || isHuman(),
|
|
1756
|
+
projectDefault: "json"
|
|
1757
|
+
});
|
|
1758
|
+
} catch (error) {
|
|
1759
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1760
|
+
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1761
|
+
process.exit(1);
|
|
1762
|
+
}
|
|
1763
|
+
const interactive = (opts.interactive ?? false) && format === "human";
|
|
1764
|
+
const resolvedOpts = interactive ? await runInteractiveInstall(opts) : opts;
|
|
1765
|
+
const channel = normalizeCleoChannel(resolvedOpts.channel);
|
|
1766
|
+
const providers = collectTargetProviders(resolvedOpts.provider, resolvedOpts.all);
|
|
1767
|
+
if (providers.length === 0) {
|
|
1768
|
+
const message = "No target providers found.";
|
|
1769
|
+
if (format === "json") {
|
|
1770
|
+
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
1771
|
+
} else {
|
|
1772
|
+
console.error(pc6.red(message));
|
|
1773
|
+
}
|
|
1774
|
+
process.exit(1);
|
|
1775
|
+
}
|
|
1776
|
+
const envMap = parseEnvAssignments(resolvedOpts.env);
|
|
1777
|
+
const profile = buildCleoProfile({
|
|
1778
|
+
channel,
|
|
1779
|
+
version: resolvedOpts.version,
|
|
1780
|
+
command: resolvedOpts.command,
|
|
1781
|
+
args: resolvedOpts.arg,
|
|
1782
|
+
env: envMap,
|
|
1783
|
+
cleoDir: resolvedOpts.cleoDir
|
|
1784
|
+
});
|
|
1785
|
+
const scope = resolvedOpts.global ? "global" : "project";
|
|
1786
|
+
if (resolvedOpts.dryRun) {
|
|
1787
|
+
if (format === "human") {
|
|
1788
|
+
console.log(pc6.bold(`Dry run: ${mode} CLEO (${channel})`));
|
|
1789
|
+
console.log(pc6.dim(`Server: ${profile.serverName} Scope: ${scope}`));
|
|
1790
|
+
console.log(pc6.dim(`Providers: ${providers.map((provider) => provider.id).join(", ")}`));
|
|
1791
|
+
console.log(pc6.dim(`Command: ${profile.config.command ?? "(none)"} ${(profile.config.args ?? []).join(" ")}`));
|
|
1792
|
+
if (profile.config.env && Object.keys(profile.config.env).length > 0) {
|
|
1793
|
+
console.log(pc6.dim(`Env: ${JSON.stringify(profile.config.env)}`));
|
|
1794
|
+
}
|
|
1795
|
+
} else {
|
|
1796
|
+
outputSuccess(operation, mvi, {
|
|
1797
|
+
action: mode,
|
|
1798
|
+
channel,
|
|
1799
|
+
serverName: profile.serverName,
|
|
1800
|
+
providers: providers.map((provider) => provider.id),
|
|
1801
|
+
scope,
|
|
1802
|
+
command: profile.config.command,
|
|
1803
|
+
args: profile.config.args ?? [],
|
|
1804
|
+
env: profile.config.env ?? {},
|
|
1805
|
+
packageSpec: profile.packageSpec,
|
|
1806
|
+
dryRun: true
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
const conflictWarnings = await detectServerConflicts(providers, scope, profile.serverName);
|
|
1812
|
+
if (format === "human" && conflictWarnings.length > 0) {
|
|
1813
|
+
console.log(pc6.yellow("Warning: potential server name conflicts detected."));
|
|
1814
|
+
for (const warning of conflictWarnings) {
|
|
1815
|
+
console.log(pc6.yellow(` - ${warning.message}`));
|
|
1816
|
+
}
|
|
1817
|
+
console.log(pc6.dim("Recovery: run with --dry-run, inspect provider config, then retry with explicit channel/profile."));
|
|
1818
|
+
console.log();
|
|
1819
|
+
}
|
|
1820
|
+
const results = await installMcpServerToAll(providers, profile.serverName, profile.config, scope);
|
|
1821
|
+
const succeeded = results.filter((result) => result.success);
|
|
1822
|
+
const validations = [];
|
|
1823
|
+
for (const result of succeeded) {
|
|
1824
|
+
const validation = await validateProfile(result.provider, scope, profile.serverName);
|
|
1825
|
+
validations.push({ providerId: result.provider.id, valid: validation.valid, reason: validation.reason });
|
|
1826
|
+
}
|
|
1827
|
+
if (succeeded.length > 0) {
|
|
1828
|
+
await recordMcpInstall(
|
|
1829
|
+
profile.serverName,
|
|
1830
|
+
profile.packageSpec ?? resolvedOpts.command ?? "cleo-dev",
|
|
1831
|
+
channel === "dev" ? "command" : "package",
|
|
1832
|
+
succeeded.map((result) => result.provider.id),
|
|
1833
|
+
resolvedOpts.global ?? false
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
if (format === "human") {
|
|
1837
|
+
formatInstallResultHuman(mode, channel, profile.serverName, scope, results, validations);
|
|
1838
|
+
}
|
|
1839
|
+
const validationFailures = validations.filter((entry) => !entry.valid);
|
|
1840
|
+
if (interactive && validationFailures.length > 0 && format === "human") {
|
|
1841
|
+
console.log(pc6.dim("Step 5/6 - Validation"));
|
|
1842
|
+
console.log(pc6.yellow(`Validation found ${validationFailures.length} issue(s).`));
|
|
1843
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1844
|
+
try {
|
|
1845
|
+
console.log(pc6.dim("Step 6/6 - Rollback"));
|
|
1846
|
+
const answer = await rl.question(pc6.dim("Rollback failed validations? [y/N] "));
|
|
1847
|
+
if (["y", "yes"].includes(answer.trim().toLowerCase())) {
|
|
1848
|
+
for (const failure of validationFailures) {
|
|
1849
|
+
const provider = providers.find((candidate) => candidate.id === failure.providerId);
|
|
1850
|
+
if (!provider) continue;
|
|
1851
|
+
await removeMcpServer(provider, profile.serverName, scope);
|
|
1852
|
+
}
|
|
1853
|
+
console.log(pc6.yellow("Rollback completed for failed provider validations."));
|
|
1854
|
+
}
|
|
1855
|
+
} finally {
|
|
1856
|
+
rl.close();
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
if (format === "json") {
|
|
1860
|
+
outputSuccess(operation, mvi, {
|
|
1861
|
+
action: mode,
|
|
1862
|
+
channel,
|
|
1863
|
+
serverName: profile.serverName,
|
|
1864
|
+
scope,
|
|
1865
|
+
command: profile.config.command,
|
|
1866
|
+
args: profile.config.args ?? [],
|
|
1867
|
+
env: profile.config.env ?? {},
|
|
1868
|
+
packageSpec: profile.packageSpec,
|
|
1869
|
+
providers: results.map((result) => ({
|
|
1870
|
+
id: result.provider.id,
|
|
1871
|
+
success: result.success,
|
|
1872
|
+
configPath: result.configPath,
|
|
1873
|
+
error: result.error,
|
|
1874
|
+
validation: validations.find((entry) => entry.providerId === result.provider.id) ?? null
|
|
1875
|
+
})),
|
|
1876
|
+
conflicts: conflictWarnings,
|
|
1877
|
+
validationStatus: validationFailures.length === 0 ? "ok" : "warning"
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
async function executeCleoUninstall(opts, operation) {
|
|
1882
|
+
const mvi = "standard";
|
|
1883
|
+
let format;
|
|
1884
|
+
try {
|
|
1885
|
+
format = resolveFormat({
|
|
1886
|
+
jsonFlag: opts.json ?? false,
|
|
1887
|
+
humanFlag: (opts.human ?? false) || isHuman(),
|
|
1888
|
+
projectDefault: "json"
|
|
1889
|
+
});
|
|
1890
|
+
} catch (error) {
|
|
1891
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1892
|
+
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1893
|
+
process.exit(1);
|
|
1894
|
+
}
|
|
1895
|
+
const channel = normalizeCleoChannel(opts.channel);
|
|
1896
|
+
const serverName = resolveCleoServerName(channel);
|
|
1897
|
+
const providers = collectTargetProviders(opts.provider, opts.all);
|
|
1898
|
+
if (providers.length === 0) {
|
|
1899
|
+
const message = "No target providers found.";
|
|
1900
|
+
if (format === "json") {
|
|
1901
|
+
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
1902
|
+
} else {
|
|
1903
|
+
console.error(pc6.red(message));
|
|
1904
|
+
}
|
|
1905
|
+
process.exit(1);
|
|
1906
|
+
}
|
|
1907
|
+
const scope = opts.global ? "global" : "project";
|
|
1908
|
+
if (opts.dryRun) {
|
|
1909
|
+
if (format === "human") {
|
|
1910
|
+
console.log(pc6.bold("Dry run: uninstall CLEO profile"));
|
|
1911
|
+
console.log(pc6.dim(`Server: ${serverName} Channel: ${channel} Scope: ${scope}`));
|
|
1912
|
+
console.log(pc6.dim(`Providers: ${providers.map((provider) => provider.id).join(", ")}`));
|
|
1913
|
+
} else {
|
|
1914
|
+
outputSuccess(operation, mvi, {
|
|
1915
|
+
action: "uninstall",
|
|
1916
|
+
channel,
|
|
1917
|
+
serverName,
|
|
1918
|
+
providers: providers.map((provider) => provider.id),
|
|
1919
|
+
scope,
|
|
1920
|
+
dryRun: true
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
const removed = [];
|
|
1926
|
+
for (const provider of providers) {
|
|
1927
|
+
const success = await removeMcpServer(provider, serverName, scope);
|
|
1928
|
+
if (success) removed.push(provider.id);
|
|
1929
|
+
}
|
|
1930
|
+
if (removed.length > 0) {
|
|
1931
|
+
await removeMcpFromLock(serverName);
|
|
1932
|
+
}
|
|
1933
|
+
if (format === "human") {
|
|
1934
|
+
const prefix = removed.length > 0 ? pc6.green("Removed") : pc6.yellow("No matching profile found for");
|
|
1935
|
+
console.log(`${prefix} ${pc6.bold(serverName)} (${channel}) on ${removed.length}/${providers.length} providers.`);
|
|
1936
|
+
}
|
|
1937
|
+
if (format === "json") {
|
|
1938
|
+
outputSuccess(operation, mvi, {
|
|
1939
|
+
action: "uninstall",
|
|
1940
|
+
channel,
|
|
1941
|
+
serverName,
|
|
1942
|
+
scope,
|
|
1943
|
+
removed,
|
|
1944
|
+
providerCount: providers.length,
|
|
1945
|
+
dryRun: false
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
async function executeCleoShow(opts, operation) {
|
|
1950
|
+
const mvi = "standard";
|
|
1951
|
+
let format;
|
|
1952
|
+
try {
|
|
1953
|
+
format = resolveFormat({
|
|
1954
|
+
jsonFlag: opts.json ?? false,
|
|
1955
|
+
humanFlag: (opts.human ?? false) || isHuman(),
|
|
1956
|
+
projectDefault: "json"
|
|
1957
|
+
});
|
|
1958
|
+
} catch (error) {
|
|
1959
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1960
|
+
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1961
|
+
process.exit(1);
|
|
1962
|
+
}
|
|
1963
|
+
const providers = collectTargetProviders(opts.provider, opts.all);
|
|
1964
|
+
if (providers.length === 0) {
|
|
1965
|
+
const message = "No target providers found.";
|
|
1966
|
+
if (format === "json") {
|
|
1967
|
+
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
1968
|
+
} else {
|
|
1969
|
+
console.error(pc6.red(message));
|
|
1970
|
+
}
|
|
1971
|
+
process.exit(1);
|
|
1972
|
+
}
|
|
1973
|
+
const channelFilter = opts.channel ? normalizeCleoChannel(opts.channel) : null;
|
|
1974
|
+
const scope = opts.global ? "global" : "project";
|
|
1975
|
+
const entries = [];
|
|
1976
|
+
for (const provider of providers) {
|
|
1977
|
+
const providerEntries = await listMcpServers(provider, scope);
|
|
1978
|
+
for (const entry of providerEntries) {
|
|
1979
|
+
const channel = resolveChannelFromServerName(entry.name);
|
|
1980
|
+
if (!channel) continue;
|
|
1981
|
+
if (channelFilter && channel !== channelFilter) continue;
|
|
1982
|
+
entries.push({
|
|
1983
|
+
provider: provider.id,
|
|
1984
|
+
serverName: entry.name,
|
|
1985
|
+
channel,
|
|
1986
|
+
command: typeof entry.config.command === "string" ? entry.config.command : void 0,
|
|
1987
|
+
args: Array.isArray(entry.config.args) ? entry.config.args.filter((value) => typeof value === "string") : [],
|
|
1988
|
+
env: typeof entry.config.env === "object" && entry.config.env !== null ? entry.config.env : {}
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (format === "human") {
|
|
1993
|
+
if (entries.length === 0) {
|
|
1994
|
+
console.log(pc6.dim("No CLEO MCP profiles found."));
|
|
1995
|
+
} else {
|
|
1996
|
+
for (const entry of entries) {
|
|
1997
|
+
console.log(`${pc6.bold(entry.provider.padEnd(22))} ${entry.serverName.padEnd(10)} ${pc6.dim(entry.channel)}`);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
if (format === "json") {
|
|
2002
|
+
outputSuccess(operation, mvi, {
|
|
2003
|
+
providers: providers.map((provider) => provider.id),
|
|
2004
|
+
scope,
|
|
2005
|
+
channel: channelFilter,
|
|
2006
|
+
profiles: entries,
|
|
2007
|
+
count: entries.length
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
function buildInstallOptions(command) {
|
|
2012
|
+
return command.requiredOption("--channel <channel>", "CLEO channel: stable|beta|dev").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Apply to all detected providers").option("-g, --global", "Use global scope").option("--version <tag>", "Tag/version for stable or beta").option("--command <command>", "Dev channel command").option("--arg <arg>", "Dev command arg (repeatable)", collect, []).option("--env <kv>", "Environment assignment KEY=value (repeatable)", collect, []).option("--cleo-dir <path>", "CLEO_DIR override for dev channel").option("--dry-run", "Preview without writing").option("-y, --yes", "Skip confirmation").option("--interactive", "Guided interactive setup").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format");
|
|
2013
|
+
}
|
|
2014
|
+
function registerMcpCleoCommands(parent) {
|
|
2015
|
+
const cleo = parent.command("cleo").description("Manage CLEO MCP channel profiles");
|
|
2016
|
+
buildInstallOptions(
|
|
2017
|
+
cleo.command("install").description("Install CLEO MCP profile by channel")
|
|
2018
|
+
).action(async (opts) => {
|
|
2019
|
+
await executeCleoInstall("install", opts, "mcp.cleo.install");
|
|
2020
|
+
});
|
|
2021
|
+
buildInstallOptions(
|
|
2022
|
+
cleo.command("update").description("Update CLEO MCP profile by channel")
|
|
2023
|
+
).action(async (opts) => {
|
|
2024
|
+
await executeCleoInstall("update", opts, "mcp.cleo.update");
|
|
2025
|
+
});
|
|
2026
|
+
cleo.command("uninstall").description("Uninstall CLEO MCP profile for a channel").requiredOption("--channel <channel>", "CLEO channel: stable|beta|dev").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Apply to all detected providers").option("-g, --global", "Use global scope").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2027
|
+
await executeCleoUninstall(opts, "mcp.cleo.uninstall");
|
|
2028
|
+
});
|
|
2029
|
+
cleo.command("show").description("Show installed CLEO MCP channel profiles").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Inspect all detected providers").option("-g, --global", "Use global scope").option("--channel <channel>", "Filter channel: stable|beta|dev").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2030
|
+
await executeCleoShow(opts, "mcp.cleo.show");
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
function registerMcpCleoCompatibilityCommands(parent) {
|
|
2034
|
+
parent.command("update").description("Update channel-managed MCP profile").argument("<name>", "Managed MCP profile name (cleo)").requiredOption("--channel <channel>", "CLEO channel: stable|beta|dev").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Apply to all detected providers").option("-g, --global", "Use global scope").option("--version <tag>", "Tag/version for stable or beta").option("--command <command>", "Dev channel command").option("--arg <arg>", "Dev command arg (repeatable)", collect, []).option("--env <kv>", "Environment assignment KEY=value (repeatable)", collect, []).option("--cleo-dir <path>", "CLEO_DIR override for dev channel").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
2035
|
+
if (name !== "cleo") {
|
|
2036
|
+
emitJsonError("mcp.update", "standard", ErrorCodes.INVALID_INPUT, "Only managed profile 'cleo' is supported by mcp update.", ErrorCategories.VALIDATION, { name });
|
|
2037
|
+
process.exit(1);
|
|
2038
|
+
}
|
|
2039
|
+
await executeCleoInstall("update", opts, "mcp.update");
|
|
2040
|
+
});
|
|
2041
|
+
parent.command("uninstall").description("Uninstall channel-managed MCP profile").argument("<name>", "Managed MCP profile name (cleo)").requiredOption("--channel <channel>", "CLEO channel: stable|beta|dev").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Apply to all detected providers").option("-g, --global", "Use global scope").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
2042
|
+
if (name !== "cleo") {
|
|
2043
|
+
emitJsonError("mcp.uninstall", "standard", ErrorCodes.INVALID_INPUT, "Only managed profile 'cleo' is supported by mcp uninstall.", ErrorCategories.VALIDATION, { name });
|
|
2044
|
+
process.exit(1);
|
|
2045
|
+
}
|
|
2046
|
+
await executeCleoUninstall(opts, "mcp.uninstall");
|
|
2047
|
+
});
|
|
2048
|
+
parent.command("show").description("Show channel-managed MCP profile").argument("<name>", "Managed MCP profile name (cleo)").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Inspect all detected providers").option("-g, --global", "Use global scope").option("--channel <channel>", "Filter channel: stable|beta|dev").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
2049
|
+
if (name !== "cleo") {
|
|
2050
|
+
emitJsonError("mcp.show", "standard", ErrorCodes.INVALID_INPUT, "Only managed profile 'cleo' is supported by mcp show.", ErrorCategories.VALIDATION, { name });
|
|
2051
|
+
process.exit(1);
|
|
2052
|
+
}
|
|
2053
|
+
await executeCleoShow(opts, "mcp.show");
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
function mapCompatibilityInstallOptions(opts) {
|
|
2057
|
+
return {
|
|
2058
|
+
channel: opts.channel,
|
|
2059
|
+
provider: [...opts.provider ?? [], ...opts.agent ?? []],
|
|
2060
|
+
all: opts.all,
|
|
2061
|
+
global: opts.global,
|
|
2062
|
+
version: opts.version,
|
|
2063
|
+
command: opts.command,
|
|
2064
|
+
arg: opts.arg ?? [],
|
|
2065
|
+
env: opts.env ?? [],
|
|
2066
|
+
cleoDir: opts.cleoDir,
|
|
2067
|
+
dryRun: opts.dryRun,
|
|
2068
|
+
yes: opts.yes,
|
|
2069
|
+
interactive: opts.interactive,
|
|
2070
|
+
json: opts.json,
|
|
2071
|
+
human: opts.human
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
function shouldUseCleoCompatibilityInstall(source, channel) {
|
|
2075
|
+
if (source.trim().toLowerCase() !== "cleo") return false;
|
|
2076
|
+
return typeof channel === "string" && channel.trim() !== "";
|
|
2077
|
+
}
|
|
2078
|
+
function registerCleoCommands(program2) {
|
|
2079
|
+
const cleo = program2.command("cleo").description("Manage CLEO channel profiles");
|
|
2080
|
+
buildInstallOptions(
|
|
2081
|
+
cleo.command("install").description("Install CLEO profile by channel")
|
|
2082
|
+
).action(async (opts) => {
|
|
2083
|
+
await executeCleoInstall("install", opts, "cleo.install");
|
|
2084
|
+
});
|
|
2085
|
+
buildInstallOptions(
|
|
2086
|
+
cleo.command("update").description("Update CLEO profile by channel")
|
|
2087
|
+
).action(async (opts) => {
|
|
2088
|
+
await executeCleoInstall("update", opts, "cleo.update");
|
|
2089
|
+
});
|
|
2090
|
+
cleo.command("uninstall").description("Uninstall CLEO profile for a channel").requiredOption("--channel <channel>", "CLEO channel: stable|beta|dev").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Apply to all detected providers").option("-g, --global", "Use global scope").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2091
|
+
await executeCleoUninstall(opts, "cleo.uninstall");
|
|
2092
|
+
});
|
|
2093
|
+
cleo.command("show").description("Show installed CLEO channel profiles").option("--provider <id>", "Target provider (repeatable)", collect, []).option("--all", "Inspect all detected providers").option("-g, --global", "Use global scope").option("--channel <channel>", "Filter channel: stable|beta|dev").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2094
|
+
await executeCleoShow(opts, "cleo.show");
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
// src/commands/mcp/detect.ts
|
|
2099
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2100
|
+
import pc7 from "picocolors";
|
|
2101
|
+
function registerMcpDetect(parent) {
|
|
2102
|
+
parent.command("detect").description("Auto-detect installed MCP tools and their configurations").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2103
|
+
const operation = "mcp.detect";
|
|
2104
|
+
const mvi = "standard";
|
|
2105
|
+
let format;
|
|
2106
|
+
try {
|
|
2107
|
+
format = resolveFormat({
|
|
2108
|
+
jsonFlag: opts.json ?? false,
|
|
2109
|
+
humanFlag: (opts.human ?? false) || isHuman(),
|
|
2110
|
+
projectDefault: "json"
|
|
2111
|
+
});
|
|
2112
|
+
} catch (error) {
|
|
2113
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2114
|
+
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
2115
|
+
process.exit(1);
|
|
2116
|
+
}
|
|
2117
|
+
const providers = getInstalledProviders();
|
|
2118
|
+
const providersResult = [];
|
|
2119
|
+
let totalConfigs = 0;
|
|
2120
|
+
for (const provider of providers) {
|
|
2121
|
+
const globalPath = resolveConfigPath(provider, "global");
|
|
2122
|
+
const projectPath = resolveConfigPath(provider, "project");
|
|
2123
|
+
const globalEntries = await listMcpServers(provider, "global");
|
|
2124
|
+
const projectEntries = await listMcpServers(provider, "project");
|
|
2125
|
+
const configsFound = (globalPath && existsSync3(globalPath) ? 1 : 0) + (projectPath && existsSync3(projectPath) ? 1 : 0);
|
|
2126
|
+
totalConfigs += configsFound;
|
|
2127
|
+
const allServers = [...globalEntries.map((e) => e.name), ...projectEntries.map((e) => e.name)];
|
|
2128
|
+
providersResult.push({
|
|
2129
|
+
id: provider.id,
|
|
2130
|
+
configsFound,
|
|
2131
|
+
servers: allServers
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
if (format === "json") {
|
|
2135
|
+
outputSuccess(operation, mvi, {
|
|
2136
|
+
providers: providersResult,
|
|
2137
|
+
totalConfigs
|
|
2138
|
+
});
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
console.log(pc7.bold(`
|
|
2142
|
+
${providers.length} provider(s) with MCP support:
|
|
2143
|
+
`));
|
|
2144
|
+
for (const provider of providersResult) {
|
|
2145
|
+
const globalPath = resolveConfigPath(providers.find((p) => p.id === provider.id), "global");
|
|
2146
|
+
const projectPath = resolveConfigPath(providers.find((p) => p.id === provider.id), "project");
|
|
2147
|
+
const hasGlobal = globalPath && existsSync3(globalPath);
|
|
2148
|
+
const hasProject = projectPath && existsSync3(projectPath);
|
|
2149
|
+
const globalIcon = hasGlobal ? pc7.green("G") : pc7.dim("-");
|
|
2150
|
+
const projectIcon = hasProject ? pc7.green("P") : pc7.dim("-");
|
|
2151
|
+
const serverList = provider.servers.length > 0 ? pc7.dim(provider.servers.join(", ")) : pc7.dim("no servers");
|
|
2152
|
+
console.log(` [${globalIcon}${projectIcon}] ${pc7.bold(provider.id.padEnd(20))} ${serverList}`);
|
|
2153
|
+
}
|
|
2154
|
+
console.log(pc7.dim("\nG = global config, P = project config"));
|
|
2155
|
+
console.log();
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
// src/commands/mcp/install.ts
|
|
2160
|
+
import pc8 from "picocolors";
|
|
1606
2161
|
function registerMcpInstall(parent) {
|
|
1607
|
-
parent.command("install").description("Install MCP server to agent configs").argument("<source>", "MCP server source (URL, npm package, or command)").option("-a, --agent <name>", "Target specific agent(s)", (v, prev) => [...prev, v], []).option("-g, --global", "Install to global/user config").option("-n, --name <name>", "Override inferred server name").option("-t, --transport <type>", "Transport type: http (default) or sse", "http").option("--header <header>", "HTTP header (Key: Value)", (v, prev) => [...prev, v], []).option("-y, --yes", "Skip confirmation").option("--all", "Install to all detected agents").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (source, opts) => {
|
|
2162
|
+
parent.command("install").description("Install MCP server to agent configs").argument("<source>", "MCP server source (URL, npm package, or command)").option("-a, --agent <name>", "Target specific agent(s)", (v, prev) => [...prev, v], []).option("--provider <id>", "Target provider ID (alias for --agent)", (v, prev) => [...prev, v], []).option("-g, --global", "Install to global/user config").option("-n, --name <name>", "Override inferred server name").option("--channel <channel>", "Managed channel profile (stable|beta|dev)").option("--version <tag>", "Managed profile tag/version for stable or beta").option("--command <command>", "Managed dev profile command").option("--arg <arg>", "Managed dev command arg (repeatable)", (v, prev) => [...prev, v], []).option("--env <kv>", "Managed env assignment KEY=value (repeatable)", (v, prev) => [...prev, v], []).option("--cleo-dir <path>", "Managed dev CLEO_DIR override").option("-t, --transport <type>", "Transport type: http (default) or sse", "http").option("--header <header>", "HTTP header (Key: Value)", (v, prev) => [...prev, v], []).option("-y, --yes", "Skip confirmation").option("--all", "Install to all detected agents").option("--interactive", "Guided interactive setup for managed profiles").option("--dry-run", "Preview without writing").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (source, opts) => {
|
|
1608
2163
|
const operation = "mcp.install";
|
|
1609
2164
|
const mvi = "standard";
|
|
1610
2165
|
let format;
|
|
@@ -1619,6 +2174,11 @@ function registerMcpInstall(parent) {
|
|
|
1619
2174
|
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1620
2175
|
process.exit(1);
|
|
1621
2176
|
}
|
|
2177
|
+
if (shouldUseCleoCompatibilityInstall(source, opts.channel)) {
|
|
2178
|
+
const cleoOpts = mapCompatibilityInstallOptions(opts);
|
|
2179
|
+
await executeCleoInstall("install", cleoOpts, operation);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
1622
2182
|
const parsed = parseSource(source);
|
|
1623
2183
|
const serverName = opts.name ?? parsed.inferredName;
|
|
1624
2184
|
const headers = {};
|
|
@@ -1634,6 +2194,8 @@ function registerMcpInstall(parent) {
|
|
|
1634
2194
|
providers = getInstalledProviders();
|
|
1635
2195
|
} else if (opts.agent.length > 0) {
|
|
1636
2196
|
providers = opts.agent.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
2197
|
+
} else if (opts.provider.length > 0) {
|
|
2198
|
+
providers = opts.provider.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
1637
2199
|
} else {
|
|
1638
2200
|
providers = getInstalledProviders();
|
|
1639
2201
|
}
|
|
@@ -1642,7 +2204,7 @@ function registerMcpInstall(parent) {
|
|
|
1642
2204
|
if (format === "json") {
|
|
1643
2205
|
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
1644
2206
|
} else {
|
|
1645
|
-
console.error(
|
|
2207
|
+
console.error(pc8.red(message));
|
|
1646
2208
|
}
|
|
1647
2209
|
process.exit(1);
|
|
1648
2210
|
}
|
|
@@ -1658,8 +2220,8 @@ function registerMcpInstall(parent) {
|
|
|
1658
2220
|
dryRun: true
|
|
1659
2221
|
});
|
|
1660
2222
|
} else {
|
|
1661
|
-
console.log(
|
|
1662
|
-
console.log(` Server: ${
|
|
2223
|
+
console.log(pc8.bold("Dry run - would install:"));
|
|
2224
|
+
console.log(` Server: ${pc8.bold(serverName)}`);
|
|
1663
2225
|
console.log(` Config: ${JSON.stringify(config, null, 2)}`);
|
|
1664
2226
|
console.log(` Scope: ${scope}`);
|
|
1665
2227
|
console.log(` Providers: ${providers.map((p) => p.id).join(", ")}`);
|
|
@@ -1667,7 +2229,7 @@ function registerMcpInstall(parent) {
|
|
|
1667
2229
|
return;
|
|
1668
2230
|
}
|
|
1669
2231
|
if (format === "human") {
|
|
1670
|
-
console.log(
|
|
2232
|
+
console.log(pc8.dim(`Installing "${serverName}" to ${providers.length} provider(s)...
|
|
1671
2233
|
`));
|
|
1672
2234
|
}
|
|
1673
2235
|
const results = await installMcpServerToAll(
|
|
@@ -1681,9 +2243,9 @@ function registerMcpInstall(parent) {
|
|
|
1681
2243
|
if (format === "human") {
|
|
1682
2244
|
for (const r of results) {
|
|
1683
2245
|
if (r.success) {
|
|
1684
|
-
console.log(` ${
|
|
2246
|
+
console.log(` ${pc8.green("\u2713")} ${r.provider.toolName.padEnd(22)} ${pc8.dim(r.configPath)}`);
|
|
1685
2247
|
} else {
|
|
1686
|
-
console.log(` ${
|
|
2248
|
+
console.log(` ${pc8.red("\u2717")} ${r.provider.toolName.padEnd(22)} ${pc8.red(r.error ?? "failed")}`);
|
|
1687
2249
|
}
|
|
1688
2250
|
}
|
|
1689
2251
|
}
|
|
@@ -1706,85 +2268,16 @@ function registerMcpInstall(parent) {
|
|
|
1706
2268
|
dryRun: false
|
|
1707
2269
|
});
|
|
1708
2270
|
} else {
|
|
1709
|
-
console.log(
|
|
2271
|
+
console.log(pc8.bold(`
|
|
1710
2272
|
${succeeded.length}/${results.length} providers configured.`));
|
|
1711
2273
|
}
|
|
1712
2274
|
});
|
|
1713
2275
|
}
|
|
1714
2276
|
|
|
1715
|
-
// src/commands/mcp/remove.ts
|
|
1716
|
-
import pc7 from "picocolors";
|
|
1717
|
-
function registerMcpRemove(parent) {
|
|
1718
|
-
parent.command("remove").description("Remove MCP server from agent configs").argument("<name>", "MCP server name to remove").option("-a, --agent <name>", "Target specific agent(s)", (v, prev) => [...prev, v], []).option("-g, --global", "Remove from global config").option("--all", "Remove from all detected agents").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
1719
|
-
const operation = "mcp.remove";
|
|
1720
|
-
const mvi = "standard";
|
|
1721
|
-
let format;
|
|
1722
|
-
try {
|
|
1723
|
-
format = resolveFormat({
|
|
1724
|
-
jsonFlag: opts.json ?? false,
|
|
1725
|
-
humanFlag: (opts.human ?? false) || isHuman(),
|
|
1726
|
-
projectDefault: "json"
|
|
1727
|
-
});
|
|
1728
|
-
} catch (error) {
|
|
1729
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1730
|
-
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1731
|
-
process.exit(1);
|
|
1732
|
-
}
|
|
1733
|
-
let providers;
|
|
1734
|
-
if (opts.all) {
|
|
1735
|
-
providers = getInstalledProviders();
|
|
1736
|
-
} else if (opts.agent.length > 0) {
|
|
1737
|
-
providers = opts.agent.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
1738
|
-
} else {
|
|
1739
|
-
providers = getInstalledProviders();
|
|
1740
|
-
}
|
|
1741
|
-
if (providers.length === 0) {
|
|
1742
|
-
const message = "No target providers found.";
|
|
1743
|
-
if (format === "json") {
|
|
1744
|
-
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
1745
|
-
} else {
|
|
1746
|
-
console.error(pc7.red(message));
|
|
1747
|
-
}
|
|
1748
|
-
process.exit(1);
|
|
1749
|
-
}
|
|
1750
|
-
const scope = opts.global ? "global" : "project";
|
|
1751
|
-
const removed = [];
|
|
1752
|
-
const notFound = [];
|
|
1753
|
-
for (const provider of providers) {
|
|
1754
|
-
const success = await removeMcpServer(provider, name, scope);
|
|
1755
|
-
if (success) {
|
|
1756
|
-
removed.push(provider.id);
|
|
1757
|
-
if (format === "human") {
|
|
1758
|
-
console.log(` ${pc7.green("\u2713")} Removed from ${provider.toolName}`);
|
|
1759
|
-
}
|
|
1760
|
-
} else {
|
|
1761
|
-
notFound.push(provider.id);
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
if (removed.length > 0) {
|
|
1765
|
-
await removeMcpFromLock(name);
|
|
1766
|
-
}
|
|
1767
|
-
if (format === "json") {
|
|
1768
|
-
outputSuccess(operation, mvi, {
|
|
1769
|
-
removed,
|
|
1770
|
-
providers: removed,
|
|
1771
|
-
notFound: notFound.length > 0 ? notFound : void 0
|
|
1772
|
-
});
|
|
1773
|
-
} else {
|
|
1774
|
-
if (removed.length > 0) {
|
|
1775
|
-
console.log(pc7.green(`
|
|
1776
|
-
\u2713 Removed "${name}" from ${removed.length} provider(s).`));
|
|
1777
|
-
} else {
|
|
1778
|
-
console.log(pc7.yellow(`Server "${name}" not found in any provider config.`));
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
2277
|
// src/commands/mcp/list.ts
|
|
1785
|
-
import
|
|
2278
|
+
import pc9 from "picocolors";
|
|
1786
2279
|
function registerMcpList(parent) {
|
|
1787
|
-
parent.command("list").description("List configured MCP servers").option("-a, --agent <name>", "List for specific agent").option("-g, --global", "List global config").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2280
|
+
parent.command("list").description("List configured MCP servers").option("-a, --agent <name>", "List for specific agent").option("--provider <id>", "Provider ID alias for --agent").option("-g, --global", "List global config").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
1788
2281
|
const operation = "mcp.list";
|
|
1789
2282
|
const mvi = "standard";
|
|
1790
2283
|
let format;
|
|
@@ -1799,15 +2292,16 @@ function registerMcpList(parent) {
|
|
|
1799
2292
|
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1800
2293
|
process.exit(1);
|
|
1801
2294
|
}
|
|
1802
|
-
const
|
|
1803
|
-
|
|
1804
|
-
|
|
2295
|
+
const selectedProvider = opts.provider ?? opts.agent;
|
|
2296
|
+
const providers = selectedProvider ? [getProvider(selectedProvider)].filter((p) => p !== void 0) : getInstalledProviders();
|
|
2297
|
+
if (selectedProvider && providers.length === 0) {
|
|
2298
|
+
const message = `Provider not found: ${selectedProvider}`;
|
|
1805
2299
|
if (format === "json") {
|
|
1806
2300
|
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND, {
|
|
1807
|
-
|
|
2301
|
+
provider: selectedProvider
|
|
1808
2302
|
});
|
|
1809
2303
|
} else {
|
|
1810
|
-
console.error(
|
|
2304
|
+
console.error(pc9.red(message));
|
|
1811
2305
|
}
|
|
1812
2306
|
process.exit(1);
|
|
1813
2307
|
}
|
|
@@ -1827,33 +2321,32 @@ function registerMcpList(parent) {
|
|
|
1827
2321
|
outputSuccess(operation, mvi, {
|
|
1828
2322
|
servers: allEntries,
|
|
1829
2323
|
count: allEntries.length,
|
|
1830
|
-
scope: opts.global ? "global" :
|
|
2324
|
+
scope: opts.global ? "global" : selectedProvider ? `agent:${selectedProvider}` : "project"
|
|
1831
2325
|
});
|
|
1832
2326
|
return;
|
|
1833
2327
|
}
|
|
1834
2328
|
if (allEntries.length === 0) {
|
|
1835
|
-
console.log(
|
|
2329
|
+
console.log(pc9.dim("No MCP servers configured."));
|
|
1836
2330
|
return;
|
|
1837
2331
|
}
|
|
1838
|
-
console.log(
|
|
2332
|
+
console.log(pc9.bold(`
|
|
1839
2333
|
${allEntries.length} MCP server(s) configured:
|
|
1840
2334
|
`));
|
|
1841
2335
|
for (const entry of allEntries) {
|
|
1842
|
-
const scopeIndicator = entry.scope === "global" ?
|
|
1843
|
-
console.log(` ${scopeIndicator}${
|
|
2336
|
+
const scopeIndicator = entry.scope === "global" ? pc9.dim("[G] ") : pc9.dim("[P] ");
|
|
2337
|
+
console.log(` ${scopeIndicator}${pc9.bold(entry.name.padEnd(25))} ${entry.command ? pc9.dim(entry.command) : ""}`);
|
|
1844
2338
|
}
|
|
1845
2339
|
console.log();
|
|
1846
|
-
console.log(
|
|
2340
|
+
console.log(pc9.dim("G = global config, P = project config"));
|
|
1847
2341
|
console.log();
|
|
1848
2342
|
});
|
|
1849
2343
|
}
|
|
1850
2344
|
|
|
1851
|
-
// src/commands/mcp/
|
|
1852
|
-
import
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
const operation = "mcp.detect";
|
|
2345
|
+
// src/commands/mcp/remove.ts
|
|
2346
|
+
import pc10 from "picocolors";
|
|
2347
|
+
function registerMcpRemove(parent) {
|
|
2348
|
+
parent.command("remove").description("Remove MCP server from agent configs").argument("<name>", "MCP server name to remove").option("-a, --agent <name>", "Target specific agent(s)", (v, prev) => [...prev, v], []).option("--provider <id>", "Target provider ID (alias for --agent)", (v, prev) => [...prev, v], []).option("-g, --global", "Remove from global config").option("--all", "Remove from all detected agents").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
2349
|
+
const operation = "mcp.remove";
|
|
1857
2350
|
const mvi = "standard";
|
|
1858
2351
|
let format;
|
|
1859
2352
|
try {
|
|
@@ -1867,45 +2360,56 @@ function registerMcpDetect(parent) {
|
|
|
1867
2360
|
emitJsonError(operation, mvi, ErrorCodes.FORMAT_CONFLICT, message, ErrorCategories.VALIDATION);
|
|
1868
2361
|
process.exit(1);
|
|
1869
2362
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
2363
|
+
let providers;
|
|
2364
|
+
if (opts.all) {
|
|
2365
|
+
providers = getInstalledProviders();
|
|
2366
|
+
} else if (opts.agent.length > 0) {
|
|
2367
|
+
providers = opts.agent.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
2368
|
+
} else if (opts.provider.length > 0) {
|
|
2369
|
+
providers = opts.provider.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
2370
|
+
} else {
|
|
2371
|
+
providers = getInstalledProviders();
|
|
2372
|
+
}
|
|
2373
|
+
if (providers.length === 0) {
|
|
2374
|
+
const message = "No target providers found.";
|
|
2375
|
+
if (format === "json") {
|
|
2376
|
+
emitJsonError(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
2377
|
+
} else {
|
|
2378
|
+
console.error(pc10.red(message));
|
|
2379
|
+
}
|
|
2380
|
+
process.exit(1);
|
|
2381
|
+
}
|
|
2382
|
+
const scope = opts.global ? "global" : "project";
|
|
2383
|
+
const removed = [];
|
|
2384
|
+
const notFound = [];
|
|
1873
2385
|
for (const provider of providers) {
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2386
|
+
const success = await removeMcpServer(provider, name, scope);
|
|
2387
|
+
if (success) {
|
|
2388
|
+
removed.push(provider.id);
|
|
2389
|
+
if (format === "human") {
|
|
2390
|
+
console.log(` ${pc10.green("\u2713")} Removed from ${provider.toolName}`);
|
|
2391
|
+
}
|
|
2392
|
+
} else {
|
|
2393
|
+
notFound.push(provider.id);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
if (removed.length > 0) {
|
|
2397
|
+
await removeMcpFromLock(name);
|
|
1886
2398
|
}
|
|
1887
2399
|
if (format === "json") {
|
|
1888
2400
|
outputSuccess(operation, mvi, {
|
|
1889
|
-
|
|
1890
|
-
|
|
2401
|
+
removed,
|
|
2402
|
+
providers: removed,
|
|
2403
|
+
notFound: notFound.length > 0 ? notFound : void 0
|
|
1891
2404
|
});
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
${
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
const projectPath = resolveConfigPath(providers.find((p) => p.id === provider.id), "project");
|
|
1900
|
-
const hasGlobal = globalPath && existsSync3(globalPath);
|
|
1901
|
-
const hasProject = projectPath && existsSync3(projectPath);
|
|
1902
|
-
const globalIcon = hasGlobal ? pc9.green("G") : pc9.dim("-");
|
|
1903
|
-
const projectIcon = hasProject ? pc9.green("P") : pc9.dim("-");
|
|
1904
|
-
const serverList = provider.servers.length > 0 ? pc9.dim(provider.servers.join(", ")) : pc9.dim("no servers");
|
|
1905
|
-
console.log(` [${globalIcon}${projectIcon}] ${pc9.bold(provider.id.padEnd(20))} ${serverList}`);
|
|
2405
|
+
} else {
|
|
2406
|
+
if (removed.length > 0) {
|
|
2407
|
+
console.log(pc10.green(`
|
|
2408
|
+
\u2713 Removed "${name}" from ${removed.length} provider(s).`));
|
|
2409
|
+
} else {
|
|
2410
|
+
console.log(pc10.yellow(`Server "${name}" not found in any provider config.`));
|
|
2411
|
+
}
|
|
1906
2412
|
}
|
|
1907
|
-
console.log(pc9.dim("\nG = global config, P = project config"));
|
|
1908
|
-
console.log();
|
|
1909
2413
|
});
|
|
1910
2414
|
}
|
|
1911
2415
|
|
|
@@ -1916,12 +2420,14 @@ function registerMcpCommands(program2) {
|
|
|
1916
2420
|
registerMcpRemove(mcp);
|
|
1917
2421
|
registerMcpList(mcp);
|
|
1918
2422
|
registerMcpDetect(mcp);
|
|
2423
|
+
registerMcpCleoCommands(mcp);
|
|
2424
|
+
registerMcpCleoCompatibilityCommands(mcp);
|
|
1919
2425
|
}
|
|
1920
2426
|
|
|
1921
2427
|
// src/commands/providers.ts
|
|
1922
2428
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1923
2429
|
import { resolveOutputFormat as resolveOutputFormat2 } from "@cleocode/lafs-protocol";
|
|
1924
|
-
import
|
|
2430
|
+
import pc11 from "picocolors";
|
|
1925
2431
|
function registerProvidersCommand(program2) {
|
|
1926
2432
|
const providers = program2.command("providers").description("Manage AI agent providers");
|
|
1927
2433
|
providers.command("list").description("List all supported providers").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").option("--tier <tier>", "Filter by priority tier (high, medium, low)").action(async (opts) => {
|
|
@@ -1955,19 +2461,19 @@ function registerProvidersCommand(program2) {
|
|
|
1955
2461
|
console.log(JSON.stringify(envelope, null, 2));
|
|
1956
2462
|
return;
|
|
1957
2463
|
}
|
|
1958
|
-
console.log(
|
|
2464
|
+
console.log(pc11.bold(`
|
|
1959
2465
|
CAMP Provider Registry v${getRegistryVersion()}`));
|
|
1960
|
-
console.log(
|
|
2466
|
+
console.log(pc11.dim(`${getProviderCount()} providers
|
|
1961
2467
|
`));
|
|
1962
2468
|
const tiers = ["high", "medium", "low"];
|
|
1963
2469
|
for (const tier of tiers) {
|
|
1964
2470
|
const tierProviders = all.filter((p) => p.priority === tier);
|
|
1965
2471
|
if (tierProviders.length === 0) continue;
|
|
1966
|
-
const tierLabel = tier === "high" ?
|
|
2472
|
+
const tierLabel = tier === "high" ? pc11.green("HIGH") : tier === "medium" ? pc11.yellow("MEDIUM") : pc11.dim("LOW");
|
|
1967
2473
|
console.log(`${tierLabel} priority:`);
|
|
1968
2474
|
for (const p of tierProviders) {
|
|
1969
|
-
const status = p.status === "active" ?
|
|
1970
|
-
console.log(` ${
|
|
2475
|
+
const status = p.status === "active" ? pc11.green("active") : p.status === "beta" ? pc11.yellow("beta") : pc11.dim(p.status);
|
|
2476
|
+
console.log(` ${pc11.bold(p.agentFlag.padEnd(20))} ${p.toolName.padEnd(22)} ${p.vendor.padEnd(16)} [${status}]`);
|
|
1971
2477
|
}
|
|
1972
2478
|
console.log();
|
|
1973
2479
|
}
|
|
@@ -2011,17 +2517,17 @@ CAMP Provider Registry v${getRegistryVersion()}`));
|
|
|
2011
2517
|
console.log(JSON.stringify(envelope, null, 2));
|
|
2012
2518
|
return;
|
|
2013
2519
|
}
|
|
2014
|
-
console.log(
|
|
2520
|
+
console.log(pc11.bold(`
|
|
2015
2521
|
Detected ${installed.length} installed providers:
|
|
2016
2522
|
`));
|
|
2017
2523
|
for (const r of installed) {
|
|
2018
2524
|
const methods = r.methods.join(", ");
|
|
2019
|
-
const project = r.projectDetected ?
|
|
2020
|
-
console.log(` ${
|
|
2525
|
+
const project = r.projectDetected ? pc11.green(" [project]") : "";
|
|
2526
|
+
console.log(` ${pc11.green("\u2713")} ${pc11.bold(r.provider.toolName.padEnd(22))} via ${pc11.dim(methods)}${project}`);
|
|
2021
2527
|
}
|
|
2022
2528
|
const notInstalled = results.filter((r) => !r.installed);
|
|
2023
2529
|
if (notInstalled.length > 0) {
|
|
2024
|
-
console.log(
|
|
2530
|
+
console.log(pc11.dim(`
|
|
2025
2531
|
${notInstalled.length} providers not detected`));
|
|
2026
2532
|
}
|
|
2027
2533
|
console.log();
|
|
@@ -2049,7 +2555,7 @@ Detected ${installed.length} installed providers:
|
|
|
2049
2555
|
id
|
|
2050
2556
|
});
|
|
2051
2557
|
} else {
|
|
2052
|
-
console.error(
|
|
2558
|
+
console.error(pc11.red(message));
|
|
2053
2559
|
}
|
|
2054
2560
|
process.exit(1);
|
|
2055
2561
|
}
|
|
@@ -2065,9 +2571,9 @@ Detected ${installed.length} installed providers:
|
|
|
2065
2571
|
console.log(JSON.stringify(envelope, null, 2));
|
|
2066
2572
|
return;
|
|
2067
2573
|
}
|
|
2068
|
-
console.log(
|
|
2574
|
+
console.log(pc11.bold(`
|
|
2069
2575
|
${provider.toolName}`));
|
|
2070
|
-
console.log(
|
|
2576
|
+
console.log(pc11.dim(`by ${provider.vendor}
|
|
2071
2577
|
`));
|
|
2072
2578
|
console.log(` ID: ${provider.id}`);
|
|
2073
2579
|
console.log(` Flag: --agent ${provider.agentFlag}`);
|
|
@@ -2083,7 +2589,7 @@ ${provider.toolName}`));
|
|
|
2083
2589
|
console.log(` Transports: ${provider.supportedTransports.join(", ")}`);
|
|
2084
2590
|
console.log(` Headers: ${provider.supportsHeaders ? "yes" : "no"}`);
|
|
2085
2591
|
console.log();
|
|
2086
|
-
console.log(
|
|
2592
|
+
console.log(pc11.dim(" Paths:"));
|
|
2087
2593
|
console.log(` Global dir: ${provider.pathGlobal}`);
|
|
2088
2594
|
console.log(` Project dir: ${provider.pathProject || "(none)"}`);
|
|
2089
2595
|
console.log(` Global config: ${provider.configPathGlobal}`);
|
|
@@ -2127,7 +2633,7 @@ function emitJsonError2(operation, mvi, code, message, category, details = {}) {
|
|
|
2127
2633
|
|
|
2128
2634
|
// src/commands/skills/install.ts
|
|
2129
2635
|
import { existsSync as existsSync4 } from "fs";
|
|
2130
|
-
import
|
|
2636
|
+
import pc12 from "picocolors";
|
|
2131
2637
|
|
|
2132
2638
|
// src/core/sources/github.ts
|
|
2133
2639
|
import { simpleGit } from "simple-git";
|
|
@@ -2211,7 +2717,7 @@ function registerSkillsInstall(parent) {
|
|
|
2211
2717
|
if (format === "json") {
|
|
2212
2718
|
emitError2(operation, mvi, ErrorCodes.PROVIDER_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
2213
2719
|
}
|
|
2214
|
-
console.error(
|
|
2720
|
+
console.error(pc12.red(message));
|
|
2215
2721
|
process.exit(1);
|
|
2216
2722
|
}
|
|
2217
2723
|
if (opts.profile) {
|
|
@@ -2223,12 +2729,12 @@ function registerSkillsInstall(parent) {
|
|
|
2223
2729
|
if (format === "json") {
|
|
2224
2730
|
emitError2(operation, mvi, ErrorCodes.INVALID_INPUT, message, ErrorCategories.VALIDATION);
|
|
2225
2731
|
}
|
|
2226
|
-
console.error(
|
|
2227
|
-
console.log(
|
|
2732
|
+
console.error(pc12.red(message));
|
|
2733
|
+
console.log(pc12.dim("Usage: caamp skills install <source> or caamp skills install --profile <name>"));
|
|
2228
2734
|
process.exit(1);
|
|
2229
2735
|
}
|
|
2230
2736
|
if (format === "human") {
|
|
2231
|
-
console.log(
|
|
2737
|
+
console.log(pc12.dim(`Installing to ${providers.length} provider(s)...`));
|
|
2232
2738
|
}
|
|
2233
2739
|
let localPath;
|
|
2234
2740
|
let cleanup;
|
|
@@ -2268,7 +2774,7 @@ function registerSkillsInstall(parent) {
|
|
|
2268
2774
|
if (format === "json") {
|
|
2269
2775
|
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
2270
2776
|
}
|
|
2271
|
-
console.error(
|
|
2777
|
+
console.error(pc12.red(message));
|
|
2272
2778
|
process.exit(1);
|
|
2273
2779
|
}
|
|
2274
2780
|
} else if (parsed.type === "gitlab" && parsed.owner && parsed.repo) {
|
|
@@ -2281,7 +2787,7 @@ function registerSkillsInstall(parent) {
|
|
|
2281
2787
|
if (format === "json") {
|
|
2282
2788
|
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
2283
2789
|
}
|
|
2284
|
-
console.error(
|
|
2790
|
+
console.error(pc12.red(message));
|
|
2285
2791
|
process.exit(1);
|
|
2286
2792
|
}
|
|
2287
2793
|
} else if (parsed.type === "local") {
|
|
@@ -2296,7 +2802,7 @@ function registerSkillsInstall(parent) {
|
|
|
2296
2802
|
if (format === "json") {
|
|
2297
2803
|
emitJsonError(operation, mvi, ErrorCodes.INVALID_INPUT, message, ErrorCategories.VALIDATION);
|
|
2298
2804
|
}
|
|
2299
|
-
console.error(
|
|
2805
|
+
console.error(pc12.red(message));
|
|
2300
2806
|
process.exit(1);
|
|
2301
2807
|
}
|
|
2302
2808
|
const catalogSkill = getSkill(parsed.inferredName);
|
|
@@ -2306,7 +2812,7 @@ function registerSkillsInstall(parent) {
|
|
|
2306
2812
|
sourceValue = `library:${catalogSkill.name}`;
|
|
2307
2813
|
sourceType = "library";
|
|
2308
2814
|
if (format === "human") {
|
|
2309
|
-
console.log(` Found in catalog: ${
|
|
2815
|
+
console.log(` Found in catalog: ${pc12.bold(catalogSkill.name)} v${catalogSkill.version} (${pc12.dim(catalogSkill.category)})`);
|
|
2310
2816
|
}
|
|
2311
2817
|
} else {
|
|
2312
2818
|
const message = `Skill not found in catalog: ${parsed.inferredName}`;
|
|
@@ -2315,8 +2821,8 @@ function registerSkillsInstall(parent) {
|
|
|
2315
2821
|
availableSkills: listSkills()
|
|
2316
2822
|
});
|
|
2317
2823
|
}
|
|
2318
|
-
console.error(
|
|
2319
|
-
console.log(
|
|
2824
|
+
console.error(pc12.red(message));
|
|
2825
|
+
console.log(pc12.dim("Available skills: " + listSkills().join(", ")));
|
|
2320
2826
|
process.exit(1);
|
|
2321
2827
|
}
|
|
2322
2828
|
} else {
|
|
@@ -2324,7 +2830,7 @@ function registerSkillsInstall(parent) {
|
|
|
2324
2830
|
if (format === "json") {
|
|
2325
2831
|
emitJsonError(operation, mvi, ErrorCodes.INVALID_FORMAT, message, ErrorCategories.VALIDATION);
|
|
2326
2832
|
}
|
|
2327
|
-
console.error(
|
|
2833
|
+
console.error(pc12.red(message));
|
|
2328
2834
|
process.exit(1);
|
|
2329
2835
|
}
|
|
2330
2836
|
}
|
|
@@ -2334,7 +2840,7 @@ function registerSkillsInstall(parent) {
|
|
|
2334
2840
|
if (format === "json") {
|
|
2335
2841
|
emitJsonError(operation, mvi, ErrorCodes.INTERNAL_ERROR, message, ErrorCategories.INTERNAL);
|
|
2336
2842
|
}
|
|
2337
|
-
console.error(
|
|
2843
|
+
console.error(pc12.red(message));
|
|
2338
2844
|
process.exit(1);
|
|
2339
2845
|
}
|
|
2340
2846
|
const result = await installSkill(
|
|
@@ -2372,14 +2878,14 @@ function registerSkillsInstall(parent) {
|
|
|
2372
2878
|
if (format === "json") {
|
|
2373
2879
|
outputSuccess(operation, mvi, summary);
|
|
2374
2880
|
} else {
|
|
2375
|
-
console.log(
|
|
2376
|
-
\u2713 Installed ${
|
|
2377
|
-
console.log(` Canonical: ${
|
|
2881
|
+
console.log(pc12.green(`
|
|
2882
|
+
\u2713 Installed ${pc12.bold(skillName)}`));
|
|
2883
|
+
console.log(` Canonical: ${pc12.dim(result.canonicalPath)}`);
|
|
2378
2884
|
console.log(` Linked to: ${result.linkedAgents.join(", ")}`);
|
|
2379
2885
|
if (result.errors.length > 0) {
|
|
2380
|
-
console.log(
|
|
2886
|
+
console.log(pc12.yellow("\nWarnings:"));
|
|
2381
2887
|
for (const err of result.errors) {
|
|
2382
|
-
console.log(` ${
|
|
2888
|
+
console.log(` ${pc12.yellow("!")} ${err}`);
|
|
2383
2889
|
}
|
|
2384
2890
|
}
|
|
2385
2891
|
}
|
|
@@ -2407,11 +2913,11 @@ function registerSkillsInstall(parent) {
|
|
|
2407
2913
|
});
|
|
2408
2914
|
console.error(JSON.stringify(envelope, null, 2));
|
|
2409
2915
|
} else {
|
|
2410
|
-
console.log(
|
|
2411
|
-
\u2717 Failed to install ${
|
|
2412
|
-
console.log(
|
|
2916
|
+
console.log(pc12.yellow(`
|
|
2917
|
+
\u2717 Failed to install ${pc12.bold(skillName)}`));
|
|
2918
|
+
console.log(pc12.yellow("Errors:"));
|
|
2413
2919
|
for (const err of result.errors) {
|
|
2414
|
-
console.log(` ${
|
|
2920
|
+
console.log(` ${pc12.yellow("!")} ${err}`);
|
|
2415
2921
|
}
|
|
2416
2922
|
}
|
|
2417
2923
|
process.exit(1);
|
|
@@ -2427,7 +2933,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2427
2933
|
if (format === "json") {
|
|
2428
2934
|
emitError2(operation, mvi, ErrorCodes.INVALID_INPUT, message, ErrorCategories.VALIDATION);
|
|
2429
2935
|
}
|
|
2430
|
-
console.error(
|
|
2936
|
+
console.error(pc12.red(message));
|
|
2431
2937
|
process.exit(1);
|
|
2432
2938
|
}
|
|
2433
2939
|
const profileSkills = resolveProfile(profileName);
|
|
@@ -2438,16 +2944,16 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2438
2944
|
availableProfiles: listProfiles()
|
|
2439
2945
|
});
|
|
2440
2946
|
}
|
|
2441
|
-
console.error(
|
|
2947
|
+
console.error(pc12.red(message));
|
|
2442
2948
|
const available = listProfiles();
|
|
2443
2949
|
if (available.length > 0) {
|
|
2444
|
-
console.log(
|
|
2950
|
+
console.log(pc12.dim("Available profiles: " + available.join(", ")));
|
|
2445
2951
|
}
|
|
2446
2952
|
process.exit(1);
|
|
2447
2953
|
}
|
|
2448
2954
|
if (format === "human") {
|
|
2449
|
-
console.log(`Installing profile ${
|
|
2450
|
-
console.log(
|
|
2955
|
+
console.log(`Installing profile ${pc12.bold(profileName)} (${profileSkills.length} skill(s))...`);
|
|
2956
|
+
console.log(pc12.dim(`Target: ${providers.length} provider(s)`));
|
|
2451
2957
|
}
|
|
2452
2958
|
const installed = [];
|
|
2453
2959
|
const failed = [];
|
|
@@ -2462,7 +2968,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2462
2968
|
);
|
|
2463
2969
|
if (result.success) {
|
|
2464
2970
|
if (format === "human") {
|
|
2465
|
-
console.log(
|
|
2971
|
+
console.log(pc12.green(` + ${name}`));
|
|
2466
2972
|
}
|
|
2467
2973
|
await recordSkillInstall(
|
|
2468
2974
|
name,
|
|
@@ -2481,7 +2987,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2481
2987
|
});
|
|
2482
2988
|
} else {
|
|
2483
2989
|
if (format === "human") {
|
|
2484
|
-
console.log(
|
|
2990
|
+
console.log(pc12.yellow(` ! ${name}: ${result.errors.join(", ")}`));
|
|
2485
2991
|
}
|
|
2486
2992
|
failed.push({
|
|
2487
2993
|
name,
|
|
@@ -2491,7 +2997,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2491
2997
|
} catch (err) {
|
|
2492
2998
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2493
2999
|
if (format === "human") {
|
|
2494
|
-
console.log(
|
|
3000
|
+
console.log(pc12.red(` x ${name}: ${errorMsg}`));
|
|
2495
3001
|
}
|
|
2496
3002
|
failed.push({
|
|
2497
3003
|
name,
|
|
@@ -2525,7 +3031,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
2525
3031
|
}
|
|
2526
3032
|
} else {
|
|
2527
3033
|
console.log(`
|
|
2528
|
-
${
|
|
3034
|
+
${pc12.green(`${installed.length} installed`)}, ${failed.length > 0 ? pc12.yellow(`${failed.length} failed`) : "0 failed"}`);
|
|
2529
3035
|
if (failed.length > 0) {
|
|
2530
3036
|
process.exit(1);
|
|
2531
3037
|
}
|
|
@@ -2533,7 +3039,7 @@ ${pc11.green(`${installed.length} installed`)}, ${failed.length > 0 ? pc11.yello
|
|
|
2533
3039
|
}
|
|
2534
3040
|
async function handleMarketplaceSource(source, _providers, _isGlobal, format, operation, mvi) {
|
|
2535
3041
|
if (format === "human") {
|
|
2536
|
-
console.log(
|
|
3042
|
+
console.log(pc12.dim(`Searching marketplace for ${source}...`));
|
|
2537
3043
|
}
|
|
2538
3044
|
const client = new MarketplaceClient();
|
|
2539
3045
|
let skill;
|
|
@@ -2544,7 +3050,7 @@ async function handleMarketplaceSource(source, _providers, _isGlobal, format, op
|
|
|
2544
3050
|
if (format === "json") {
|
|
2545
3051
|
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
2546
3052
|
}
|
|
2547
|
-
console.error(
|
|
3053
|
+
console.error(pc12.red(message));
|
|
2548
3054
|
return { success: false };
|
|
2549
3055
|
}
|
|
2550
3056
|
if (!skill) {
|
|
@@ -2552,11 +3058,11 @@ async function handleMarketplaceSource(source, _providers, _isGlobal, format, op
|
|
|
2552
3058
|
if (format === "json") {
|
|
2553
3059
|
emitJsonError(operation, mvi, ErrorCodes.SKILL_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
2554
3060
|
}
|
|
2555
|
-
console.error(
|
|
3061
|
+
console.error(pc12.red(message));
|
|
2556
3062
|
return { success: false };
|
|
2557
3063
|
}
|
|
2558
3064
|
if (format === "human") {
|
|
2559
|
-
console.log(` Found: ${
|
|
3065
|
+
console.log(` Found: ${pc12.bold(skill.name)} by ${skill.author} (${pc12.dim(skill.repoFullName)})`);
|
|
2560
3066
|
}
|
|
2561
3067
|
const parsed = parseSource(skill.githubUrl);
|
|
2562
3068
|
if (parsed.type !== "github" || !parsed.owner || !parsed.repo) {
|
|
@@ -2564,7 +3070,7 @@ async function handleMarketplaceSource(source, _providers, _isGlobal, format, op
|
|
|
2564
3070
|
if (format === "json") {
|
|
2565
3071
|
emitJsonError(operation, mvi, ErrorCodes.INVALID_FORMAT, message, ErrorCategories.VALIDATION);
|
|
2566
3072
|
}
|
|
2567
|
-
console.error(
|
|
3073
|
+
console.error(pc12.red(message));
|
|
2568
3074
|
return { success: false };
|
|
2569
3075
|
}
|
|
2570
3076
|
try {
|
|
@@ -2604,13 +3110,13 @@ async function handleMarketplaceSource(source, _providers, _isGlobal, format, op
|
|
|
2604
3110
|
if (format === "json") {
|
|
2605
3111
|
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
2606
3112
|
}
|
|
2607
|
-
console.error(
|
|
3113
|
+
console.error(pc12.red(message));
|
|
2608
3114
|
return { success: false };
|
|
2609
3115
|
}
|
|
2610
3116
|
}
|
|
2611
3117
|
|
|
2612
3118
|
// src/commands/skills/remove.ts
|
|
2613
|
-
import
|
|
3119
|
+
import pc13 from "picocolors";
|
|
2614
3120
|
function registerSkillsRemove(parent) {
|
|
2615
3121
|
parent.command("remove").description("Remove installed skill(s)").argument("[name]", "Skill name to remove").option("-g, --global", "Remove from global scope").option("-y, --yes", "Skip confirmation").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
2616
3122
|
const operation = "skills.remove";
|
|
@@ -2649,14 +3155,14 @@ function registerSkillsRemove(parent) {
|
|
|
2649
3155
|
return;
|
|
2650
3156
|
}
|
|
2651
3157
|
if (removed.length > 0) {
|
|
2652
|
-
console.log(
|
|
3158
|
+
console.log(pc13.green(`\u2713 Removed ${pc13.bold(name)} from: ${removed.join(", ")}`));
|
|
2653
3159
|
await removeSkillFromLock(name);
|
|
2654
3160
|
} else {
|
|
2655
|
-
console.log(
|
|
3161
|
+
console.log(pc13.yellow(`Skill ${name} not found in any provider.`));
|
|
2656
3162
|
}
|
|
2657
3163
|
if (result.errors.length > 0) {
|
|
2658
3164
|
for (const err of result.errors) {
|
|
2659
|
-
console.log(
|
|
3165
|
+
console.log(pc13.red(` ${err}`));
|
|
2660
3166
|
}
|
|
2661
3167
|
}
|
|
2662
3168
|
} else {
|
|
@@ -2669,7 +3175,7 @@ function registerSkillsRemove(parent) {
|
|
|
2669
3175
|
count: { removed: 0, total: 0 }
|
|
2670
3176
|
});
|
|
2671
3177
|
} else {
|
|
2672
|
-
console.log(
|
|
3178
|
+
console.log(pc13.dim("No skills installed."));
|
|
2673
3179
|
}
|
|
2674
3180
|
return;
|
|
2675
3181
|
}
|
|
@@ -2682,11 +3188,11 @@ function registerSkillsRemove(parent) {
|
|
|
2682
3188
|
});
|
|
2683
3189
|
return;
|
|
2684
3190
|
}
|
|
2685
|
-
console.log(
|
|
3191
|
+
console.log(pc13.bold("Installed skills:"));
|
|
2686
3192
|
for (const s of skills) {
|
|
2687
3193
|
console.log(` ${s}`);
|
|
2688
3194
|
}
|
|
2689
|
-
console.log(
|
|
3195
|
+
console.log(pc13.dim("\nUse: caamp skills remove <name>"));
|
|
2690
3196
|
}
|
|
2691
3197
|
});
|
|
2692
3198
|
}
|
|
@@ -2694,7 +3200,7 @@ function registerSkillsRemove(parent) {
|
|
|
2694
3200
|
// src/commands/skills/list.ts
|
|
2695
3201
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2696
3202
|
import { resolveOutputFormat as resolveOutputFormat3 } from "@cleocode/lafs-protocol";
|
|
2697
|
-
import
|
|
3203
|
+
import pc14 from "picocolors";
|
|
2698
3204
|
function registerSkillsList(parent) {
|
|
2699
3205
|
parent.command("list").description("List installed skills").option("-g, --global", "List global skills").option("-a, --agent <name>", "List skills for specific agent").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
2700
3206
|
const operation = "skills.list";
|
|
@@ -2721,7 +3227,7 @@ function registerSkillsList(parent) {
|
|
|
2721
3227
|
agent: opts.agent
|
|
2722
3228
|
});
|
|
2723
3229
|
} else {
|
|
2724
|
-
console.error(
|
|
3230
|
+
console.error(pc14.red(message));
|
|
2725
3231
|
}
|
|
2726
3232
|
process.exit(1);
|
|
2727
3233
|
}
|
|
@@ -2749,19 +3255,19 @@ function registerSkillsList(parent) {
|
|
|
2749
3255
|
return;
|
|
2750
3256
|
}
|
|
2751
3257
|
if (skills.length === 0) {
|
|
2752
|
-
console.log(
|
|
3258
|
+
console.log(pc14.dim("No skills found."));
|
|
2753
3259
|
return;
|
|
2754
3260
|
}
|
|
2755
|
-
console.log(
|
|
3261
|
+
console.log(pc14.bold(`
|
|
2756
3262
|
${skills.length} skill(s) found:
|
|
2757
3263
|
`));
|
|
2758
3264
|
skills.forEach((skill, index) => {
|
|
2759
3265
|
const num = (index + 1).toString().padStart(2);
|
|
2760
|
-
console.log(` ${
|
|
3266
|
+
console.log(` ${pc14.cyan(num)}. ${pc14.bold(skill.name.padEnd(30))} ${pc14.dim(skill.metadata?.description ?? "")}`);
|
|
2761
3267
|
});
|
|
2762
|
-
console.log(
|
|
3268
|
+
console.log(pc14.dim(`
|
|
2763
3269
|
Install with: caamp skills install <name>`));
|
|
2764
|
-
console.log(
|
|
3270
|
+
console.log(pc14.dim(`Remove with: caamp skills remove <name>`));
|
|
2765
3271
|
});
|
|
2766
3272
|
}
|
|
2767
3273
|
function buildEnvelope5(operation, mvi, result, error) {
|
|
@@ -2801,7 +3307,7 @@ import { randomUUID as randomUUID5 } from "crypto";
|
|
|
2801
3307
|
import {
|
|
2802
3308
|
resolveOutputFormat as resolveOutputFormat4
|
|
2803
3309
|
} from "@cleocode/lafs-protocol";
|
|
2804
|
-
import
|
|
3310
|
+
import pc15 from "picocolors";
|
|
2805
3311
|
var SkillsFindValidationError = class extends Error {
|
|
2806
3312
|
code;
|
|
2807
3313
|
constructor(code, message) {
|
|
@@ -2827,7 +3333,7 @@ function registerSkillsFind(parent) {
|
|
|
2827
3333
|
if (opts.json) {
|
|
2828
3334
|
emitJsonError4(operation, mvi, "E_FORMAT_CONFLICT", message, "VALIDATION");
|
|
2829
3335
|
} else {
|
|
2830
|
-
console.error(
|
|
3336
|
+
console.error(pc15.red(message));
|
|
2831
3337
|
}
|
|
2832
3338
|
process.exit(1);
|
|
2833
3339
|
}
|
|
@@ -2888,19 +3394,19 @@ function registerSkillsFind(parent) {
|
|
|
2888
3394
|
query: query ?? null
|
|
2889
3395
|
});
|
|
2890
3396
|
} else {
|
|
2891
|
-
console.error(
|
|
3397
|
+
console.error(pc15.red(`Recommendation failed: ${message}`));
|
|
2892
3398
|
}
|
|
2893
3399
|
process.exit(1);
|
|
2894
3400
|
}
|
|
2895
3401
|
}
|
|
2896
3402
|
if (!query) {
|
|
2897
|
-
console.log(
|
|
3403
|
+
console.log(pc15.dim("Usage: caamp skills find <query>"));
|
|
2898
3404
|
return;
|
|
2899
3405
|
}
|
|
2900
3406
|
const limit = parseInt(opts.limit, 10);
|
|
2901
3407
|
const client = new MarketplaceClient();
|
|
2902
3408
|
if (format === "human") {
|
|
2903
|
-
console.log(
|
|
3409
|
+
console.log(pc15.dim(`Searching marketplaces for "${query}"...
|
|
2904
3410
|
`));
|
|
2905
3411
|
}
|
|
2906
3412
|
let results;
|
|
@@ -2914,7 +3420,7 @@ function registerSkillsFind(parent) {
|
|
|
2914
3420
|
limit
|
|
2915
3421
|
});
|
|
2916
3422
|
} else {
|
|
2917
|
-
console.error(
|
|
3423
|
+
console.error(pc15.red(`Marketplace search failed: ${message}`));
|
|
2918
3424
|
}
|
|
2919
3425
|
process.exit(1);
|
|
2920
3426
|
}
|
|
@@ -2934,21 +3440,21 @@ function registerSkillsFind(parent) {
|
|
|
2934
3440
|
return;
|
|
2935
3441
|
}
|
|
2936
3442
|
if (results.length === 0) {
|
|
2937
|
-
console.log(
|
|
3443
|
+
console.log(pc15.yellow("No results found."));
|
|
2938
3444
|
return;
|
|
2939
3445
|
}
|
|
2940
|
-
console.log(
|
|
3446
|
+
console.log(pc15.dim(`Found ${results.length} result(s) for "${query}":
|
|
2941
3447
|
`));
|
|
2942
3448
|
results.forEach((skill, index) => {
|
|
2943
3449
|
const num = (index + 1).toString().padStart(2);
|
|
2944
|
-
const stars = skill.stars > 0 ?
|
|
2945
|
-
console.log(` ${
|
|
2946
|
-
console.log(` ${
|
|
2947
|
-
console.log(` ${
|
|
3450
|
+
const stars = skill.stars > 0 ? pc15.yellow(`\u2605 ${formatStars(skill.stars)}`) : "";
|
|
3451
|
+
console.log(` ${pc15.cyan(num)}. ${pc15.bold(skill.scopedName)} ${stars}`);
|
|
3452
|
+
console.log(` ${pc15.dim(skill.description?.slice(0, 80) ?? "")}`);
|
|
3453
|
+
console.log(` ${pc15.dim(`from ${skill.source}`)}`);
|
|
2948
3454
|
console.log();
|
|
2949
3455
|
});
|
|
2950
|
-
console.log(
|
|
2951
|
-
console.log(
|
|
3456
|
+
console.log(pc15.dim("Install with: caamp skills install <name>"));
|
|
3457
|
+
console.log(pc15.dim("Or select by number: caamp skills install <n>"));
|
|
2952
3458
|
});
|
|
2953
3459
|
}
|
|
2954
3460
|
function formatStars(n) {
|
|
@@ -3062,7 +3568,7 @@ function emitJsonError4(operation, mvi, code, message, category, details = {}) {
|
|
|
3062
3568
|
}
|
|
3063
3569
|
|
|
3064
3570
|
// src/commands/skills/check.ts
|
|
3065
|
-
import
|
|
3571
|
+
import pc16 from "picocolors";
|
|
3066
3572
|
function registerSkillsCheck(parent) {
|
|
3067
3573
|
parent.command("check").description("Check for available skill updates").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
3068
3574
|
const operation = "skills.check";
|
|
@@ -3089,12 +3595,12 @@ function registerSkillsCheck(parent) {
|
|
|
3089
3595
|
total: 0
|
|
3090
3596
|
});
|
|
3091
3597
|
} else {
|
|
3092
|
-
console.log(
|
|
3598
|
+
console.log(pc16.dim("No tracked skills."));
|
|
3093
3599
|
}
|
|
3094
3600
|
return;
|
|
3095
3601
|
}
|
|
3096
3602
|
if (format === "human") {
|
|
3097
|
-
console.log(
|
|
3603
|
+
console.log(pc16.dim(`Checking ${entries.length} skill(s) for updates...
|
|
3098
3604
|
`));
|
|
3099
3605
|
}
|
|
3100
3606
|
const skillResults = [];
|
|
@@ -3130,37 +3636,37 @@ function registerSkillsCheck(parent) {
|
|
|
3130
3636
|
for (const r of skillResults) {
|
|
3131
3637
|
let statusLabel;
|
|
3132
3638
|
if (r.hasUpdate) {
|
|
3133
|
-
statusLabel =
|
|
3639
|
+
statusLabel = pc16.yellow("update available");
|
|
3134
3640
|
} else if (r.currentVersion !== "unknown") {
|
|
3135
|
-
statusLabel =
|
|
3641
|
+
statusLabel = pc16.green("up to date");
|
|
3136
3642
|
} else {
|
|
3137
|
-
statusLabel =
|
|
3643
|
+
statusLabel = pc16.dim("unknown");
|
|
3138
3644
|
}
|
|
3139
|
-
console.log(` ${
|
|
3645
|
+
console.log(` ${pc16.bold(r.name.padEnd(30))} ${statusLabel}`);
|
|
3140
3646
|
if (r.currentVersion !== "unknown" || r.latestVersion !== "unknown") {
|
|
3141
3647
|
const current = r.currentVersion !== "unknown" ? r.currentVersion.slice(0, 12) : "?";
|
|
3142
3648
|
const latest = r.latestVersion !== "unknown" ? r.latestVersion : "?";
|
|
3143
3649
|
if (r.hasUpdate) {
|
|
3144
|
-
console.log(` ${
|
|
3650
|
+
console.log(` ${pc16.dim("current:")} ${current} ${pc16.dim("->")} ${pc16.cyan(latest)}`);
|
|
3145
3651
|
} else {
|
|
3146
|
-
console.log(` ${
|
|
3652
|
+
console.log(` ${pc16.dim("version:")} ${current}`);
|
|
3147
3653
|
}
|
|
3148
3654
|
}
|
|
3149
|
-
console.log(` ${
|
|
3150
|
-
console.log(` ${
|
|
3655
|
+
console.log(` ${pc16.dim(`source: ${r.source}`)}`);
|
|
3656
|
+
console.log(` ${pc16.dim(`agents: ${r.agents.join(", ")}`)}`);
|
|
3151
3657
|
console.log();
|
|
3152
3658
|
}
|
|
3153
3659
|
if (updatesAvailable > 0) {
|
|
3154
|
-
console.log(
|
|
3155
|
-
console.log(
|
|
3660
|
+
console.log(pc16.yellow(`${updatesAvailable} update(s) available.`));
|
|
3661
|
+
console.log(pc16.dim("Run `caamp skills update` to update all."));
|
|
3156
3662
|
} else {
|
|
3157
|
-
console.log(
|
|
3663
|
+
console.log(pc16.green("All skills are up to date."));
|
|
3158
3664
|
}
|
|
3159
3665
|
});
|
|
3160
3666
|
}
|
|
3161
3667
|
|
|
3162
3668
|
// src/commands/skills/update.ts
|
|
3163
|
-
import
|
|
3669
|
+
import pc17 from "picocolors";
|
|
3164
3670
|
function registerSkillsUpdate(parent) {
|
|
3165
3671
|
parent.command("update").description("Update all outdated skills").option("-y, --yes", "Skip confirmation").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
3166
3672
|
const operation = "skills.update";
|
|
@@ -3188,12 +3694,12 @@ function registerSkillsUpdate(parent) {
|
|
|
3188
3694
|
count: { updated: 0, failed: 0, skipped: 0 }
|
|
3189
3695
|
});
|
|
3190
3696
|
} else {
|
|
3191
|
-
console.log(
|
|
3697
|
+
console.log(pc17.dim("No tracked skills to update."));
|
|
3192
3698
|
}
|
|
3193
3699
|
return;
|
|
3194
3700
|
}
|
|
3195
3701
|
if (format === "human") {
|
|
3196
|
-
console.log(
|
|
3702
|
+
console.log(pc17.dim(`Checking ${entries.length} skill(s) for updates...`));
|
|
3197
3703
|
}
|
|
3198
3704
|
const outdated = [];
|
|
3199
3705
|
for (const [name] of entries) {
|
|
@@ -3215,29 +3721,29 @@ function registerSkillsUpdate(parent) {
|
|
|
3215
3721
|
count: { updated: 0, failed: 0, skipped: 0 }
|
|
3216
3722
|
});
|
|
3217
3723
|
} else {
|
|
3218
|
-
console.log(
|
|
3724
|
+
console.log(pc17.green("\nAll skills are up to date."));
|
|
3219
3725
|
}
|
|
3220
3726
|
return;
|
|
3221
3727
|
}
|
|
3222
3728
|
if (format === "human") {
|
|
3223
|
-
console.log(
|
|
3729
|
+
console.log(pc17.yellow(`
|
|
3224
3730
|
${outdated.length} skill(s) have updates available:
|
|
3225
3731
|
`));
|
|
3226
3732
|
for (const skill of outdated) {
|
|
3227
3733
|
const current = skill.currentVersion?.slice(0, 12) ?? "?";
|
|
3228
3734
|
const latest = skill.latestVersion ?? "?";
|
|
3229
|
-
console.log(` ${
|
|
3735
|
+
console.log(` ${pc17.bold(skill.name)} ${pc17.dim(current)} ${pc17.dim("->")} ${pc17.cyan(latest)}`);
|
|
3230
3736
|
}
|
|
3231
3737
|
}
|
|
3232
3738
|
if (!opts.yes && format === "human") {
|
|
3233
3739
|
const readline = await import("readline");
|
|
3234
3740
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3235
3741
|
const answer = await new Promise((resolve) => {
|
|
3236
|
-
rl.question(
|
|
3742
|
+
rl.question(pc17.dim("\nProceed with update? [y/N] "), resolve);
|
|
3237
3743
|
});
|
|
3238
3744
|
rl.close();
|
|
3239
3745
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
3240
|
-
console.log(
|
|
3746
|
+
console.log(pc17.dim("Update cancelled."));
|
|
3241
3747
|
return;
|
|
3242
3748
|
}
|
|
3243
3749
|
}
|
|
@@ -3251,7 +3757,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3251
3757
|
const entry = tracked[skill.name];
|
|
3252
3758
|
if (!entry) continue;
|
|
3253
3759
|
if (format === "human") {
|
|
3254
|
-
console.log(
|
|
3760
|
+
console.log(pc17.dim(`Updating ${pc17.bold(skill.name)}...`));
|
|
3255
3761
|
}
|
|
3256
3762
|
try {
|
|
3257
3763
|
const parsed = parseSource(entry.source);
|
|
@@ -3267,7 +3773,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3267
3773
|
cleanup = result.cleanup;
|
|
3268
3774
|
} else {
|
|
3269
3775
|
if (format === "human") {
|
|
3270
|
-
console.log(
|
|
3776
|
+
console.log(pc17.yellow(` Skipped ${skill.name}: source type "${parsed.type}" does not support auto-update`));
|
|
3271
3777
|
}
|
|
3272
3778
|
skipped.push(skill.name);
|
|
3273
3779
|
continue;
|
|
@@ -3276,7 +3782,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3276
3782
|
const providers = entry.agents.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
3277
3783
|
if (providers.length === 0) {
|
|
3278
3784
|
if (format === "human") {
|
|
3279
|
-
console.log(
|
|
3785
|
+
console.log(pc17.yellow(` Skipped ${skill.name}: no valid providers found`));
|
|
3280
3786
|
}
|
|
3281
3787
|
skipped.push(skill.name);
|
|
3282
3788
|
continue;
|
|
@@ -3301,18 +3807,18 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3301
3807
|
skill.latestVersion
|
|
3302
3808
|
);
|
|
3303
3809
|
if (format === "human") {
|
|
3304
|
-
console.log(
|
|
3810
|
+
console.log(pc17.green(` Updated ${pc17.bold(skill.name)}`));
|
|
3305
3811
|
}
|
|
3306
3812
|
updated.push(skill.name);
|
|
3307
3813
|
} else {
|
|
3308
3814
|
if (format === "human") {
|
|
3309
|
-
console.log(
|
|
3815
|
+
console.log(pc17.red(` Failed to update ${skill.name}: no agents linked`));
|
|
3310
3816
|
}
|
|
3311
3817
|
failed.push({ name: skill.name, error: "no agents linked" });
|
|
3312
3818
|
}
|
|
3313
3819
|
if (installResult.errors.length > 0 && format === "human") {
|
|
3314
3820
|
for (const err of installResult.errors) {
|
|
3315
|
-
console.log(
|
|
3821
|
+
console.log(pc17.yellow(` ${err}`));
|
|
3316
3822
|
}
|
|
3317
3823
|
}
|
|
3318
3824
|
} finally {
|
|
@@ -3321,7 +3827,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3321
3827
|
} catch (err) {
|
|
3322
3828
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3323
3829
|
if (format === "human") {
|
|
3324
|
-
console.log(
|
|
3830
|
+
console.log(pc17.red(` Failed to update ${skill.name}: ${msg}`));
|
|
3325
3831
|
}
|
|
3326
3832
|
failed.push({ name: skill.name, error: msg });
|
|
3327
3833
|
}
|
|
@@ -3341,10 +3847,10 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3341
3847
|
}
|
|
3342
3848
|
console.log();
|
|
3343
3849
|
if (updated.length > 0) {
|
|
3344
|
-
console.log(
|
|
3850
|
+
console.log(pc17.green(`Updated ${updated.length} skill(s).`));
|
|
3345
3851
|
}
|
|
3346
3852
|
if (failed.length > 0) {
|
|
3347
|
-
console.log(
|
|
3853
|
+
console.log(pc17.red(`Failed to update ${failed.length} skill(s).`));
|
|
3348
3854
|
}
|
|
3349
3855
|
});
|
|
3350
3856
|
}
|
|
@@ -3353,7 +3859,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3353
3859
|
import { existsSync as existsSync5 } from "fs";
|
|
3354
3860
|
import { mkdir, writeFile } from "fs/promises";
|
|
3355
3861
|
import { join as join5 } from "path";
|
|
3356
|
-
import
|
|
3862
|
+
import pc18 from "picocolors";
|
|
3357
3863
|
function registerSkillsInit(parent) {
|
|
3358
3864
|
parent.command("init").description("Create a new SKILL.md template").argument("[name]", "Skill name").option("-d, --dir <path>", "Output directory", ".").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (name, opts) => {
|
|
3359
3865
|
const operation = "skills.init";
|
|
@@ -3379,7 +3885,7 @@ function registerSkillsInit(parent) {
|
|
|
3379
3885
|
path: skillDir
|
|
3380
3886
|
});
|
|
3381
3887
|
} else {
|
|
3382
|
-
console.error(
|
|
3888
|
+
console.error(pc18.red(message));
|
|
3383
3889
|
}
|
|
3384
3890
|
process.exit(1);
|
|
3385
3891
|
}
|
|
@@ -3418,17 +3924,17 @@ Show example inputs and expected outputs.
|
|
|
3418
3924
|
outputSuccess(operation, mvi, result);
|
|
3419
3925
|
return;
|
|
3420
3926
|
}
|
|
3421
|
-
console.log(
|
|
3422
|
-
console.log(
|
|
3423
|
-
console.log(
|
|
3424
|
-
console.log(
|
|
3425
|
-
console.log(
|
|
3927
|
+
console.log(pc18.green(`\u2713 Created skill template: ${skillDir}/SKILL.md`));
|
|
3928
|
+
console.log(pc18.dim("\nNext steps:"));
|
|
3929
|
+
console.log(pc18.dim(" 1. Edit SKILL.md with your instructions"));
|
|
3930
|
+
console.log(pc18.dim(` 2. Validate: caamp skills validate ${join5(skillDir, "SKILL.md")}`));
|
|
3931
|
+
console.log(pc18.dim(` 3. Install: caamp skills install ${skillDir}`));
|
|
3426
3932
|
});
|
|
3427
3933
|
}
|
|
3428
3934
|
|
|
3429
3935
|
// src/commands/skills/audit.ts
|
|
3430
3936
|
import { existsSync as existsSync6, statSync } from "fs";
|
|
3431
|
-
import
|
|
3937
|
+
import pc19 from "picocolors";
|
|
3432
3938
|
function registerSkillsAudit(parent) {
|
|
3433
3939
|
parent.command("audit").description("Security scan skill files (46+ rules, SARIF output)").argument("[path]", "Path to SKILL.md or directory", ".").option("--sarif", "Output in SARIF format (raw SARIF, not LAFS envelope)").option("--json", "Output as JSON (LAFS envelope)").option("--human", "Output in human-readable format").action(async (path, opts) => {
|
|
3434
3940
|
const operation = "skills.audit";
|
|
@@ -3517,7 +4023,7 @@ function registerSkillsAudit(parent) {
|
|
|
3517
4023
|
outputSuccess(operation, mvi, summary2);
|
|
3518
4024
|
return;
|
|
3519
4025
|
}
|
|
3520
|
-
console.log(
|
|
4026
|
+
console.log(pc19.dim("No SKILL.md files found to scan."));
|
|
3521
4027
|
return;
|
|
3522
4028
|
}
|
|
3523
4029
|
const summary = {
|
|
@@ -3551,21 +4057,21 @@ function registerSkillsAudit(parent) {
|
|
|
3551
4057
|
}
|
|
3552
4058
|
let totalFindings = 0;
|
|
3553
4059
|
for (const result of results) {
|
|
3554
|
-
const icon = result.passed ?
|
|
4060
|
+
const icon = result.passed ? pc19.green("\u2713") : pc19.red("\u2717");
|
|
3555
4061
|
console.log(`
|
|
3556
|
-
${icon} ${
|
|
4062
|
+
${icon} ${pc19.bold(result.file)} (score: ${result.score}/100)`);
|
|
3557
4063
|
if (result.findings.length === 0) {
|
|
3558
|
-
console.log(
|
|
4064
|
+
console.log(pc19.dim(" No issues found."));
|
|
3559
4065
|
continue;
|
|
3560
4066
|
}
|
|
3561
4067
|
totalFindings += result.findings.length;
|
|
3562
4068
|
for (const f of result.findings) {
|
|
3563
|
-
const sev = f.rule.severity === "critical" ?
|
|
4069
|
+
const sev = f.rule.severity === "critical" ? pc19.red(f.rule.severity) : f.rule.severity === "high" ? pc19.red(f.rule.severity) : f.rule.severity === "medium" ? pc19.yellow(f.rule.severity) : pc19.dim(f.rule.severity);
|
|
3564
4070
|
console.log(` ${sev.padEnd(20)} ${f.rule.id} ${f.rule.name}`);
|
|
3565
|
-
console.log(` ${
|
|
4071
|
+
console.log(` ${pc19.dim(`L${f.line}: ${f.context.slice(0, 80)}`)}`);
|
|
3566
4072
|
}
|
|
3567
4073
|
}
|
|
3568
|
-
console.log(
|
|
4074
|
+
console.log(pc19.bold(`
|
|
3569
4075
|
${results.length} file(s) scanned, ${totalFindings} finding(s)`));
|
|
3570
4076
|
if (!allPassed) {
|
|
3571
4077
|
process.exit(1);
|
|
@@ -3575,7 +4081,7 @@ ${results.length} file(s) scanned, ${totalFindings} finding(s)`));
|
|
|
3575
4081
|
|
|
3576
4082
|
// src/commands/skills/validate.ts
|
|
3577
4083
|
import { resolveOutputFormat as resolveOutputFormat5 } from "@cleocode/lafs-protocol";
|
|
3578
|
-
import
|
|
4084
|
+
import pc20 from "picocolors";
|
|
3579
4085
|
function registerSkillsValidate(parent) {
|
|
3580
4086
|
parent.command("validate").description("Validate SKILL.md format").argument("[path]", "Path to SKILL.md", "SKILL.md").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (path, opts) => {
|
|
3581
4087
|
const operation = "skills.validate";
|
|
@@ -3602,7 +4108,7 @@ function registerSkillsValidate(parent) {
|
|
|
3602
4108
|
path
|
|
3603
4109
|
});
|
|
3604
4110
|
} else {
|
|
3605
|
-
console.error(
|
|
4111
|
+
console.error(pc20.red(message));
|
|
3606
4112
|
}
|
|
3607
4113
|
process.exit(1);
|
|
3608
4114
|
}
|
|
@@ -3624,12 +4130,12 @@ function registerSkillsValidate(parent) {
|
|
|
3624
4130
|
console.log(JSON.stringify(envelope, null, 2));
|
|
3625
4131
|
} else {
|
|
3626
4132
|
if (result.valid) {
|
|
3627
|
-
console.log(
|
|
4133
|
+
console.log(pc20.green(`\u2713 ${path} is valid`));
|
|
3628
4134
|
} else {
|
|
3629
|
-
console.log(
|
|
4135
|
+
console.log(pc20.red(`\u2717 ${path} has validation errors`));
|
|
3630
4136
|
}
|
|
3631
4137
|
for (const issue of result.issues) {
|
|
3632
|
-
const icon = issue.level === "error" ?
|
|
4138
|
+
const icon = issue.level === "error" ? pc20.red("\u2717") : pc20.yellow("!");
|
|
3633
4139
|
console.log(` ${icon} [${issue.field}] ${issue.message}`);
|
|
3634
4140
|
}
|
|
3635
4141
|
}
|
|
@@ -3665,6 +4171,7 @@ program.hook("preAction", (thisCommand) => {
|
|
|
3665
4171
|
registerProvidersCommand(program);
|
|
3666
4172
|
registerSkillsCommands(program);
|
|
3667
4173
|
registerMcpCommands(program);
|
|
4174
|
+
registerCleoCommands(program);
|
|
3668
4175
|
registerInstructionsCommands(program);
|
|
3669
4176
|
registerConfigCommand(program);
|
|
3670
4177
|
registerDoctorCommand(program);
|