@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/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-GR47LTXR.js";
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 existsSync4 } from "fs";
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 && existsSync4(globalPath) ? 1 : 0) + (projectPath && existsSync4(projectPath) ? 1 : 0);
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 && existsSync4(globalPath);
2251
- const hasProject = projectPath && existsSync4(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 existsSync5 } from "fs";
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 && !existsSync5(result.localPath)) {
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((resolve2) => {
3845
- rl.question(pc17.dim("\nProceed with update? [y/N] "), resolve2);
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 existsSync6 } from "fs";
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 (existsSync6(skillDir)) {
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 existsSync7, statSync } from "fs";
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 (!existsSync7(path)) {
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);