@cleocode/caamp 1.2.1 → 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-GR47LTXR.js → chunk-O2YG5HT7.js} +162 -26
- package/dist/chunk-O2YG5HT7.js.map +1 -0
- package/dist/cli.js +39 -141
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +15 -1
- package/package.json +1 -1
- package/dist/chunk-GR47LTXR.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";
|
|
@@ -1604,134 +1610,6 @@ function registerInstructionsCommands(program2) {
|
|
|
1604
1610
|
// src/commands/mcp/cleo.ts
|
|
1605
1611
|
import { createInterface } from "readline/promises";
|
|
1606
1612
|
import pc6 from "picocolors";
|
|
1607
|
-
|
|
1608
|
-
// src/core/mcp/cleo.ts
|
|
1609
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
1610
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1611
|
-
import { homedir as homedir2 } from "os";
|
|
1612
|
-
import { isAbsolute, resolve } from "path";
|
|
1613
|
-
var CLEO_SERVER_NAMES = {
|
|
1614
|
-
stable: "cleo",
|
|
1615
|
-
beta: "cleo-beta",
|
|
1616
|
-
dev: "cleo-dev"
|
|
1617
|
-
};
|
|
1618
|
-
var CLEO_MCP_NPM_PACKAGE = "@cleocode/cleo";
|
|
1619
|
-
var CLEO_DEV_DIR_DEFAULT = "~/.cleo-dev";
|
|
1620
|
-
function normalizeCleoChannel(value) {
|
|
1621
|
-
if (!value || value.trim() === "") return "stable";
|
|
1622
|
-
const normalized = value.trim().toLowerCase();
|
|
1623
|
-
if (normalized === "stable" || normalized === "beta" || normalized === "dev") {
|
|
1624
|
-
return normalized;
|
|
1625
|
-
}
|
|
1626
|
-
throw new Error(`Invalid channel "${value}". Expected stable, beta, or dev.`);
|
|
1627
|
-
}
|
|
1628
|
-
function resolveCleoServerName(channel) {
|
|
1629
|
-
return CLEO_SERVER_NAMES[channel];
|
|
1630
|
-
}
|
|
1631
|
-
function resolveChannelFromServerName(serverName) {
|
|
1632
|
-
if (serverName === CLEO_SERVER_NAMES.stable) return "stable";
|
|
1633
|
-
if (serverName === CLEO_SERVER_NAMES.beta) return "beta";
|
|
1634
|
-
if (serverName === CLEO_SERVER_NAMES.dev) return "dev";
|
|
1635
|
-
return null;
|
|
1636
|
-
}
|
|
1637
|
-
function splitCommand(command, explicitArgs = []) {
|
|
1638
|
-
if (explicitArgs.length > 0) {
|
|
1639
|
-
return { command, args: explicitArgs };
|
|
1640
|
-
}
|
|
1641
|
-
const parts = command.trim().split(/\s+/);
|
|
1642
|
-
const binary = parts[0] ?? "";
|
|
1643
|
-
if (!binary) {
|
|
1644
|
-
throw new Error("Command is required for dev channel.");
|
|
1645
|
-
}
|
|
1646
|
-
return {
|
|
1647
|
-
command: binary,
|
|
1648
|
-
args: parts.slice(1)
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
function normalizeEnv(env, channel, cleoDir) {
|
|
1652
|
-
const result = { ...env ?? {} };
|
|
1653
|
-
if (channel === "dev" && !result.CLEO_DIR) {
|
|
1654
|
-
result.CLEO_DIR = cleoDir ?? CLEO_DEV_DIR_DEFAULT;
|
|
1655
|
-
}
|
|
1656
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
1657
|
-
}
|
|
1658
|
-
function resolvePackageSpec(channel, version) {
|
|
1659
|
-
const tag = version?.trim() || (channel === "stable" ? "latest" : "beta");
|
|
1660
|
-
return `${CLEO_MCP_NPM_PACKAGE}@${tag}`;
|
|
1661
|
-
}
|
|
1662
|
-
function buildCleoProfile(options) {
|
|
1663
|
-
const channel = options.channel;
|
|
1664
|
-
const serverName = resolveCleoServerName(channel);
|
|
1665
|
-
if (channel === "dev") {
|
|
1666
|
-
if (!options.command || options.command.trim() === "") {
|
|
1667
|
-
throw new Error("Dev channel requires --command.");
|
|
1668
|
-
}
|
|
1669
|
-
const parsed = splitCommand(options.command, options.args ?? []);
|
|
1670
|
-
const env = normalizeEnv(options.env, channel, options.cleoDir);
|
|
1671
|
-
return {
|
|
1672
|
-
channel,
|
|
1673
|
-
serverName,
|
|
1674
|
-
config: {
|
|
1675
|
-
command: parsed.command,
|
|
1676
|
-
args: parsed.args,
|
|
1677
|
-
...env ? { env } : {}
|
|
1678
|
-
}
|
|
1679
|
-
};
|
|
1680
|
-
}
|
|
1681
|
-
const packageSpec = resolvePackageSpec(channel, options.version);
|
|
1682
|
-
return {
|
|
1683
|
-
channel,
|
|
1684
|
-
serverName,
|
|
1685
|
-
packageSpec,
|
|
1686
|
-
config: {
|
|
1687
|
-
command: "npx",
|
|
1688
|
-
args: ["-y", packageSpec, "cleo-mcp"]
|
|
1689
|
-
}
|
|
1690
|
-
};
|
|
1691
|
-
}
|
|
1692
|
-
function expandHome(pathValue) {
|
|
1693
|
-
if (pathValue === "~") return homedir2();
|
|
1694
|
-
if (pathValue.startsWith("~/")) {
|
|
1695
|
-
return resolve(homedir2(), pathValue.slice(2));
|
|
1696
|
-
}
|
|
1697
|
-
return pathValue;
|
|
1698
|
-
}
|
|
1699
|
-
function checkCommandReachability(command) {
|
|
1700
|
-
const hasPathSeparator = command.includes("/") || command.includes("\\");
|
|
1701
|
-
if (hasPathSeparator || command.startsWith("~")) {
|
|
1702
|
-
const expanded = expandHome(command);
|
|
1703
|
-
const candidate = isAbsolute(expanded) ? expanded : resolve(process.cwd(), expanded);
|
|
1704
|
-
if (existsSync3(candidate)) {
|
|
1705
|
-
return { reachable: true, method: "path", detail: candidate };
|
|
1706
|
-
}
|
|
1707
|
-
return { reachable: false, method: "path", detail: candidate };
|
|
1708
|
-
}
|
|
1709
|
-
try {
|
|
1710
|
-
const lookup = process.platform === "win32" ? "where" : "which";
|
|
1711
|
-
execFileSync2(lookup, [command], { stdio: "pipe" });
|
|
1712
|
-
return { reachable: true, method: "lookup", detail: command };
|
|
1713
|
-
} catch {
|
|
1714
|
-
return { reachable: false, method: "lookup", detail: command };
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
function parseEnvAssignments(values) {
|
|
1718
|
-
const env = {};
|
|
1719
|
-
for (const value of values) {
|
|
1720
|
-
const idx = value.indexOf("=");
|
|
1721
|
-
if (idx <= 0) {
|
|
1722
|
-
throw new Error(`Invalid --env value "${value}". Use KEY=value.`);
|
|
1723
|
-
}
|
|
1724
|
-
const key = value.slice(0, idx).trim();
|
|
1725
|
-
const val = value.slice(idx + 1).trim();
|
|
1726
|
-
if (!key) {
|
|
1727
|
-
throw new Error(`Invalid --env value "${value}". Key cannot be empty.`);
|
|
1728
|
-
}
|
|
1729
|
-
env[key] = val;
|
|
1730
|
-
}
|
|
1731
|
-
return env;
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// src/commands/mcp/cleo.ts
|
|
1735
1613
|
function collect(value, previous) {
|
|
1736
1614
|
return [...previous, value];
|
|
1737
1615
|
}
|
|
@@ -2197,9 +2075,28 @@ function shouldUseCleoCompatibilityInstall(source, channel) {
|
|
|
2197
2075
|
if (source.trim().toLowerCase() !== "cleo") return false;
|
|
2198
2076
|
return typeof channel === "string" && channel.trim() !== "";
|
|
2199
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
|
+
}
|
|
2200
2097
|
|
|
2201
2098
|
// src/commands/mcp/detect.ts
|
|
2202
|
-
import { existsSync as
|
|
2099
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2203
2100
|
import pc7 from "picocolors";
|
|
2204
2101
|
function registerMcpDetect(parent) {
|
|
2205
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) => {
|
|
@@ -2225,7 +2122,7 @@ function registerMcpDetect(parent) {
|
|
|
2225
2122
|
const projectPath = resolveConfigPath(provider, "project");
|
|
2226
2123
|
const globalEntries = await listMcpServers(provider, "global");
|
|
2227
2124
|
const projectEntries = await listMcpServers(provider, "project");
|
|
2228
|
-
const configsFound = (globalPath &&
|
|
2125
|
+
const configsFound = (globalPath && existsSync3(globalPath) ? 1 : 0) + (projectPath && existsSync3(projectPath) ? 1 : 0);
|
|
2229
2126
|
totalConfigs += configsFound;
|
|
2230
2127
|
const allServers = [...globalEntries.map((e) => e.name), ...projectEntries.map((e) => e.name)];
|
|
2231
2128
|
providersResult.push({
|
|
@@ -2247,8 +2144,8 @@ ${providers.length} provider(s) with MCP support:
|
|
|
2247
2144
|
for (const provider of providersResult) {
|
|
2248
2145
|
const globalPath = resolveConfigPath(providers.find((p) => p.id === provider.id), "global");
|
|
2249
2146
|
const projectPath = resolveConfigPath(providers.find((p) => p.id === provider.id), "project");
|
|
2250
|
-
const hasGlobal = globalPath &&
|
|
2251
|
-
const hasProject = projectPath &&
|
|
2147
|
+
const hasGlobal = globalPath && existsSync3(globalPath);
|
|
2148
|
+
const hasProject = projectPath && existsSync3(projectPath);
|
|
2252
2149
|
const globalIcon = hasGlobal ? pc7.green("G") : pc7.dim("-");
|
|
2253
2150
|
const projectIcon = hasProject ? pc7.green("P") : pc7.dim("-");
|
|
2254
2151
|
const serverList = provider.servers.length > 0 ? pc7.dim(provider.servers.join(", ")) : pc7.dim("no servers");
|
|
@@ -2735,7 +2632,7 @@ function emitJsonError2(operation, mvi, code, message, category, details = {}) {
|
|
|
2735
2632
|
}
|
|
2736
2633
|
|
|
2737
2634
|
// src/commands/skills/install.ts
|
|
2738
|
-
import { existsSync as
|
|
2635
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2739
2636
|
import pc12 from "picocolors";
|
|
2740
2637
|
|
|
2741
2638
|
// src/core/sources/github.ts
|
|
@@ -3185,7 +3082,7 @@ async function handleMarketplaceSource(source, _providers, _isGlobal, format, op
|
|
|
3185
3082
|
for (const subPath of subPathCandidates) {
|
|
3186
3083
|
try {
|
|
3187
3084
|
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, subPath);
|
|
3188
|
-
if (subPath && !
|
|
3085
|
+
if (subPath && !existsSync4(result.localPath)) {
|
|
3189
3086
|
await result.cleanup();
|
|
3190
3087
|
continue;
|
|
3191
3088
|
}
|
|
@@ -3841,8 +3738,8 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3841
3738
|
if (!opts.yes && format === "human") {
|
|
3842
3739
|
const readline = await import("readline");
|
|
3843
3740
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3844
|
-
const answer = await new Promise((
|
|
3845
|
-
rl.question(pc17.dim("\nProceed with update? [y/N] "),
|
|
3741
|
+
const answer = await new Promise((resolve) => {
|
|
3742
|
+
rl.question(pc17.dim("\nProceed with update? [y/N] "), resolve);
|
|
3846
3743
|
});
|
|
3847
3744
|
rl.close();
|
|
3848
3745
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
@@ -3959,7 +3856,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
3959
3856
|
}
|
|
3960
3857
|
|
|
3961
3858
|
// src/commands/skills/init.ts
|
|
3962
|
-
import { existsSync as
|
|
3859
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3963
3860
|
import { mkdir, writeFile } from "fs/promises";
|
|
3964
3861
|
import { join as join5 } from "path";
|
|
3965
3862
|
import pc18 from "picocolors";
|
|
@@ -3981,7 +3878,7 @@ function registerSkillsInit(parent) {
|
|
|
3981
3878
|
}
|
|
3982
3879
|
const skillName = name ?? "my-skill";
|
|
3983
3880
|
const skillDir = join5(opts.dir, skillName);
|
|
3984
|
-
if (
|
|
3881
|
+
if (existsSync5(skillDir)) {
|
|
3985
3882
|
const message = `Directory already exists: ${skillDir}`;
|
|
3986
3883
|
if (format === "json") {
|
|
3987
3884
|
emitJsonError(operation, mvi, ErrorCodes.INVALID_CONSTRAINT, message, ErrorCategories.CONFLICT, {
|
|
@@ -4036,13 +3933,13 @@ Show example inputs and expected outputs.
|
|
|
4036
3933
|
}
|
|
4037
3934
|
|
|
4038
3935
|
// src/commands/skills/audit.ts
|
|
4039
|
-
import { existsSync as
|
|
3936
|
+
import { existsSync as existsSync6, statSync } from "fs";
|
|
4040
3937
|
import pc19 from "picocolors";
|
|
4041
3938
|
function registerSkillsAudit(parent) {
|
|
4042
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) => {
|
|
4043
3940
|
const operation = "skills.audit";
|
|
4044
3941
|
const mvi = "standard";
|
|
4045
|
-
if (!
|
|
3942
|
+
if (!existsSync6(path)) {
|
|
4046
3943
|
const message = `Path not found: ${path}`;
|
|
4047
3944
|
if (opts.sarif) {
|
|
4048
3945
|
console.error(JSON.stringify({
|
|
@@ -4274,6 +4171,7 @@ program.hook("preAction", (thisCommand) => {
|
|
|
4274
4171
|
registerProvidersCommand(program);
|
|
4275
4172
|
registerSkillsCommands(program);
|
|
4276
4173
|
registerMcpCommands(program);
|
|
4174
|
+
registerCleoCommands(program);
|
|
4277
4175
|
registerInstructionsCommands(program);
|
|
4278
4176
|
registerConfigCommand(program);
|
|
4279
4177
|
registerDoctorCommand(program);
|