@cannbot-ai/install-helper 0.0.2-beta.37 → 0.0.2-beta.39
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/index.js +329 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -195,8 +195,19 @@ function isDirectory(path) {
|
|
|
195
195
|
// src/core/registry.ts
|
|
196
196
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
197
197
|
var __dirname2 = dirname2(__filename2);
|
|
198
|
+
function findPluginsDir() {
|
|
199
|
+
const candidates = [
|
|
200
|
+
join2(__dirname2, "plugins.d"),
|
|
201
|
+
join2(__dirname2, "..", "plugins.d"),
|
|
202
|
+
join2(__dirname2, "..", "..", "plugins.d")
|
|
203
|
+
];
|
|
204
|
+
for (const dir of candidates) {
|
|
205
|
+
if (existsSync(dir)) return dir;
|
|
206
|
+
}
|
|
207
|
+
return candidates[0];
|
|
208
|
+
}
|
|
198
209
|
function loadPluginsFromYaml() {
|
|
199
|
-
const pluginsDir =
|
|
210
|
+
const pluginsDir = findPluginsDir();
|
|
200
211
|
const defaultsPath = join2(pluginsDir, "_defaults.yml");
|
|
201
212
|
let defaults = {};
|
|
202
213
|
try {
|
|
@@ -388,6 +399,9 @@ function getConfigRoot(tool, level, base) {
|
|
|
388
399
|
function getConfigFileName(tool) {
|
|
389
400
|
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
390
401
|
}
|
|
402
|
+
function getAgentsFileName(tool) {
|
|
403
|
+
return getConfigFileName(tool);
|
|
404
|
+
}
|
|
391
405
|
function getSkillsDir(configRoot) {
|
|
392
406
|
return join3(configRoot, "skills");
|
|
393
407
|
}
|
|
@@ -1502,9 +1516,9 @@ function createRepositoryManager(customPath) {
|
|
|
1502
1516
|
}
|
|
1503
1517
|
|
|
1504
1518
|
// src/core/installer.ts
|
|
1505
|
-
import { existsSync as
|
|
1506
|
-
import { join as
|
|
1507
|
-
import { execa as
|
|
1519
|
+
import { existsSync as existsSync12 } from "fs";
|
|
1520
|
+
import { join as join12 } from "path";
|
|
1521
|
+
import { execa as execa4 } from "execa";
|
|
1508
1522
|
|
|
1509
1523
|
// src/core/record.ts
|
|
1510
1524
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
@@ -1836,39 +1850,211 @@ async function showRestorePrompt(backups) {
|
|
|
1836
1850
|
return choice;
|
|
1837
1851
|
}
|
|
1838
1852
|
|
|
1839
|
-
// src/core/installer.ts
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1853
|
+
// src/core/plugin-installer.ts
|
|
1854
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, realpathSync, copyFileSync as copyFileSync2, cpSync, writeFileSync as writeFileSync3, readFileSync as readFileSync8 } from "fs";
|
|
1855
|
+
import { join as join11 } from "path";
|
|
1856
|
+
import { execa as execa3 } from "execa";
|
|
1857
|
+
function readPluginManifest(pluginDir) {
|
|
1858
|
+
const manifestPath = join11(pluginDir, "plugin-manifest.json");
|
|
1859
|
+
if (!existsSync11(manifestPath)) return null;
|
|
1860
|
+
try {
|
|
1861
|
+
const content = JSON.parse(readFileSync8(manifestPath, "utf-8"));
|
|
1862
|
+
if (!content || !content.id) return null;
|
|
1863
|
+
return content;
|
|
1864
|
+
} catch {
|
|
1865
|
+
return null;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
function installLink(source, target) {
|
|
1869
|
+
try {
|
|
1870
|
+
const resolved = realpathSync(source);
|
|
1871
|
+
if (existsSync11(target) || isSymlink(target)) {
|
|
1872
|
+
unlinkSync4(target);
|
|
1873
|
+
}
|
|
1874
|
+
try {
|
|
1875
|
+
symlinkSync(resolved, target);
|
|
1876
|
+
return "symlink";
|
|
1877
|
+
} catch (e) {
|
|
1878
|
+
if (e.code === "EPERM") {
|
|
1879
|
+
cpSync(resolved, target, { recursive: true });
|
|
1880
|
+
return "copy";
|
|
1881
|
+
}
|
|
1882
|
+
throw e;
|
|
1883
|
+
}
|
|
1884
|
+
} catch {
|
|
1885
|
+
return "failed";
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function installConfigFile(pluginDir, configFile, tool, level, configRoot, installPath) {
|
|
1889
|
+
const sourcePath = join11(pluginDir, configFile);
|
|
1890
|
+
if (!existsSync11(sourcePath)) return;
|
|
1891
|
+
const agentsFileName = getAgentsFileName(tool);
|
|
1892
|
+
const isProjectLevel = level === "project";
|
|
1893
|
+
let primaryTarget;
|
|
1894
|
+
if (isProjectLevel) {
|
|
1895
|
+
primaryTarget = join11(installPath, agentsFileName);
|
|
1896
|
+
} else {
|
|
1897
|
+
primaryTarget = join11(configRoot, agentsFileName);
|
|
1898
|
+
}
|
|
1899
|
+
if (existsSync11(primaryTarget) || isSymlink(primaryTarget)) {
|
|
1900
|
+
unlinkSync4(primaryTarget);
|
|
1901
|
+
}
|
|
1902
|
+
try {
|
|
1903
|
+
symlinkSync(realpathSync(sourcePath), primaryTarget);
|
|
1904
|
+
} catch (e) {
|
|
1905
|
+
if (e.code === "EPERM") {
|
|
1906
|
+
copyFileSync2(sourcePath, primaryTarget);
|
|
1907
|
+
} else {
|
|
1908
|
+
throw e;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
if (isProjectLevel && primaryTarget !== join11(configRoot, agentsFileName)) {
|
|
1912
|
+
const configRootTarget = join11(configRoot, agentsFileName);
|
|
1913
|
+
if (existsSync11(configRootTarget) || isSymlink(configRootTarget)) {
|
|
1914
|
+
unlinkSync4(configRootTarget);
|
|
1915
|
+
}
|
|
1916
|
+
try {
|
|
1917
|
+
symlinkSync(realpathSync(sourcePath), configRootTarget);
|
|
1918
|
+
} catch (e) {
|
|
1919
|
+
if (e.code === "EPERM") {
|
|
1920
|
+
copyFileSync2(sourcePath, configRootTarget);
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
async function installExternalRepos(repos, repoPath) {
|
|
1926
|
+
if (!repos || repos.length === 0) return;
|
|
1927
|
+
for (const repo of repos) {
|
|
1928
|
+
const targetDir = join11(repoPath, repo.dir);
|
|
1929
|
+
if (existsSync11(targetDir)) {
|
|
1930
|
+
logger.info(` ${repo.dir} already exists, skipping clone`);
|
|
1931
|
+
continue;
|
|
1932
|
+
}
|
|
1933
|
+
const args = ["clone"];
|
|
1934
|
+
if (repo.depth) {
|
|
1935
|
+
args.push("--depth", String(repo.depth));
|
|
1936
|
+
}
|
|
1937
|
+
if (repo.recursive) {
|
|
1938
|
+
args.push("--recursive");
|
|
1939
|
+
}
|
|
1940
|
+
args.push(repo.url, targetDir);
|
|
1941
|
+
try {
|
|
1942
|
+
await execa3("git", args, { timeout: 12e4 });
|
|
1943
|
+
} catch {
|
|
1944
|
+
logger.warn(` git clone failed: ${repo.url}, clone manually: git clone ${repo.url} ${repo.dir}`);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
function writeCannbotManifest(configRoot, pluginId, version, level, tool, skills, agents) {
|
|
1949
|
+
const manifest = {
|
|
1950
|
+
brand: "CANNBot",
|
|
1951
|
+
version,
|
|
1952
|
+
team: pluginId,
|
|
1953
|
+
level,
|
|
1954
|
+
tool,
|
|
1955
|
+
installed_skills: skills,
|
|
1956
|
+
installed_agents: agents,
|
|
1957
|
+
brand_dir: configRoot,
|
|
1958
|
+
install_time: (/* @__PURE__ */ new Date()).toISOString()
|
|
1959
|
+
};
|
|
1960
|
+
const manifestPath = join11(configRoot, "cannbot-manifest.json");
|
|
1961
|
+
writeFileSync3(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
1962
|
+
return manifest;
|
|
1963
|
+
}
|
|
1964
|
+
async function installViaManifest(manifest, pluginDir, repoPath, tool, level, installPath) {
|
|
1965
|
+
const cwd = installPath || process.cwd();
|
|
1966
|
+
const configRoot = getConfigRoot(tool, level, installPath);
|
|
1967
|
+
try {
|
|
1968
|
+
const skillsDir = join11(configRoot, "skills");
|
|
1969
|
+
const agentsDir = join11(configRoot, "agents");
|
|
1970
|
+
mkdirSync5(skillsDir, { recursive: true });
|
|
1971
|
+
mkdirSync5(agentsDir, { recursive: true });
|
|
1972
|
+
const installedSkills = [];
|
|
1973
|
+
const installedAgents = [];
|
|
1974
|
+
for (const source of manifest.skills) {
|
|
1975
|
+
const sourceDir = join11(repoPath, source.dir);
|
|
1976
|
+
if (!existsSync11(sourceDir)) {
|
|
1977
|
+
logger.warn(` Skill source not found: ${source.dir}`);
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
for (const skillName of source.skills) {
|
|
1981
|
+
const skillPath = join11(sourceDir, skillName);
|
|
1982
|
+
if (!existsSync11(skillPath)) {
|
|
1983
|
+
logger.warn(` Skill not found: ${skillName} in ${source.dir}`);
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
const targetPath = join11(skillsDir, skillName);
|
|
1987
|
+
const result = installLink(skillPath, targetPath);
|
|
1988
|
+
if (result !== "failed") {
|
|
1989
|
+
installedSkills.push(skillName);
|
|
1990
|
+
} else {
|
|
1991
|
+
logger.warn(` Failed to install skill: ${skillName}`);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
for (const agentName of manifest.agents) {
|
|
1996
|
+
const agentFile = agentName.endsWith(".md") ? agentName : `${agentName}.md`;
|
|
1997
|
+
const agentPath = join11(pluginDir, "agents", agentFile);
|
|
1998
|
+
if (!existsSync11(agentPath)) {
|
|
1999
|
+
logger.warn(` Agent not found: ${agentFile}`);
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
const targetPath = join11(agentsDir, agentFile);
|
|
2003
|
+
const result = installLink(agentPath, targetPath);
|
|
2004
|
+
if (result !== "failed") {
|
|
2005
|
+
installedAgents.push(agentFile);
|
|
2006
|
+
} else {
|
|
2007
|
+
logger.warn(` Failed to install agent: ${agentFile}`);
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
installConfigFile(pluginDir, manifest.configFile, tool, level, configRoot, cwd);
|
|
2011
|
+
await installExternalRepos(manifest.externalRepos, repoPath);
|
|
2012
|
+
const cannbotManifest = writeCannbotManifest(
|
|
2013
|
+
configRoot,
|
|
2014
|
+
manifest.id,
|
|
2015
|
+
manifest.version || "1.0.0",
|
|
2016
|
+
level,
|
|
2017
|
+
tool,
|
|
2018
|
+
installedSkills,
|
|
2019
|
+
installedAgents
|
|
2020
|
+
);
|
|
2021
|
+
return {
|
|
2022
|
+
success: true,
|
|
2023
|
+
skillsCount: installedSkills.length,
|
|
2024
|
+
agentsCount: installedAgents.length,
|
|
2025
|
+
errors: [],
|
|
2026
|
+
manifest: cannbotManifest
|
|
2027
|
+
};
|
|
2028
|
+
} catch (error) {
|
|
1843
2029
|
return {
|
|
1844
2030
|
success: false,
|
|
1845
|
-
pluginId: opts.pluginId,
|
|
1846
2031
|
skillsCount: 0,
|
|
1847
2032
|
agentsCount: 0,
|
|
1848
|
-
errors: [t("
|
|
1849
|
-
|
|
2033
|
+
errors: [error instanceof Error ? error.message : t("error_unknown")],
|
|
2034
|
+
manifest: null
|
|
1850
2035
|
};
|
|
1851
2036
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// src/core/installer.ts
|
|
2040
|
+
async function installPlugin(opts) {
|
|
2041
|
+
const plugin = getPluginById(opts.pluginId);
|
|
2042
|
+
if (!plugin) {
|
|
1854
2043
|
return {
|
|
1855
2044
|
success: false,
|
|
1856
2045
|
pluginId: opts.pluginId,
|
|
1857
2046
|
skillsCount: 0,
|
|
1858
2047
|
agentsCount: 0,
|
|
1859
|
-
errors: [t("
|
|
2048
|
+
errors: [t("error_plugin_not_found") + ": " + opts.pluginId],
|
|
1860
2049
|
warnings: []
|
|
1861
2050
|
};
|
|
1862
2051
|
}
|
|
1863
|
-
const
|
|
1864
|
-
if (opts.installPath) {
|
|
1865
|
-
args.push(opts.installPath);
|
|
1866
|
-
}
|
|
2052
|
+
const pluginDir = join12(opts.repoPath, plugin.dir);
|
|
1867
2053
|
const cwd = opts.installPath || process.cwd();
|
|
1868
2054
|
const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
|
|
1869
|
-
const agentsFile =
|
|
2055
|
+
const agentsFile = join12(configRoot, getAgentsFileName(opts.tool));
|
|
1870
2056
|
let backupInfo = null;
|
|
1871
|
-
if (
|
|
2057
|
+
if (existsSync12(agentsFile)) {
|
|
1872
2058
|
const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
|
|
1873
2059
|
if (currentPlugin && currentPlugin.pluginId !== opts.pluginId) {
|
|
1874
2060
|
let choice = "overwrite";
|
|
@@ -1909,6 +2095,73 @@ async function installPlugin(opts) {
|
|
|
1909
2095
|
logger.success(`${t("backup_created")}: ${backupInfo.filePath}`);
|
|
1910
2096
|
}
|
|
1911
2097
|
}
|
|
2098
|
+
const pluginManifest = readPluginManifest(pluginDir);
|
|
2099
|
+
if (pluginManifest) {
|
|
2100
|
+
const result = await installViaManifest(
|
|
2101
|
+
pluginManifest,
|
|
2102
|
+
pluginDir,
|
|
2103
|
+
opts.repoPath,
|
|
2104
|
+
opts.tool,
|
|
2105
|
+
opts.level,
|
|
2106
|
+
opts.installPath
|
|
2107
|
+
);
|
|
2108
|
+
if (result.success) {
|
|
2109
|
+
try {
|
|
2110
|
+
const record = scanInstalledFiles(
|
|
2111
|
+
opts.pluginId,
|
|
2112
|
+
plugin.displayName,
|
|
2113
|
+
opts.tool,
|
|
2114
|
+
opts.level,
|
|
2115
|
+
cwd,
|
|
2116
|
+
configRoot,
|
|
2117
|
+
result.manifest
|
|
2118
|
+
);
|
|
2119
|
+
if (backupInfo) {
|
|
2120
|
+
record.backup = {
|
|
2121
|
+
filePath: backupInfo.filePath,
|
|
2122
|
+
fromPluginId: backupInfo.pluginId,
|
|
2123
|
+
fromPluginName: backupInfo.pluginName,
|
|
2124
|
+
backupTime: backupInfo.backupTime
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
writeRecord(record);
|
|
2128
|
+
} catch {
|
|
2129
|
+
logger.warn(t("record_write_failed"));
|
|
2130
|
+
}
|
|
2131
|
+
return {
|
|
2132
|
+
success: true,
|
|
2133
|
+
pluginId: opts.pluginId,
|
|
2134
|
+
skillsCount: result.skillsCount,
|
|
2135
|
+
agentsCount: result.agentsCount,
|
|
2136
|
+
errors: result.errors,
|
|
2137
|
+
warnings: []
|
|
2138
|
+
};
|
|
2139
|
+
} else {
|
|
2140
|
+
return {
|
|
2141
|
+
success: false,
|
|
2142
|
+
pluginId: opts.pluginId,
|
|
2143
|
+
skillsCount: 0,
|
|
2144
|
+
agentsCount: 0,
|
|
2145
|
+
errors: result.errors,
|
|
2146
|
+
warnings: []
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
const scriptPath = join12(pluginDir, plugin.script);
|
|
2151
|
+
if (!existsSync12(scriptPath)) {
|
|
2152
|
+
return {
|
|
2153
|
+
success: false,
|
|
2154
|
+
pluginId: opts.pluginId,
|
|
2155
|
+
skillsCount: 0,
|
|
2156
|
+
agentsCount: 0,
|
|
2157
|
+
errors: [t("error_script_not_found").replace("{path}", scriptPath)],
|
|
2158
|
+
warnings: []
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
const args = [opts.level, opts.tool];
|
|
2162
|
+
if (opts.installPath) {
|
|
2163
|
+
args.push(opts.installPath);
|
|
2164
|
+
}
|
|
1912
2165
|
try {
|
|
1913
2166
|
const shell = process.platform === "win32" ? "sh" : "bash";
|
|
1914
2167
|
const execOptions = {
|
|
@@ -1917,7 +2170,7 @@ async function installPlugin(opts) {
|
|
|
1917
2170
|
stdio: "pipe",
|
|
1918
2171
|
input: opts.yes ? "y\n" : void 0
|
|
1919
2172
|
};
|
|
1920
|
-
await
|
|
2173
|
+
await execa4(shell, [scriptPath, ...args], execOptions);
|
|
1921
2174
|
const manifest = readManifest(configRoot);
|
|
1922
2175
|
let skillsCount = 0;
|
|
1923
2176
|
let agentsCount = 0;
|
|
@@ -1972,17 +2225,17 @@ async function installPlugin(opts) {
|
|
|
1972
2225
|
}
|
|
1973
2226
|
|
|
1974
2227
|
// src/core/skill-installer.ts
|
|
1975
|
-
import { existsSync as
|
|
1976
|
-
import { join as
|
|
2228
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readdirSync as readdirSync4, rmdirSync, realpathSync as realpathSync2 } from "fs";
|
|
2229
|
+
import { join as join13, dirname as dirname7 } from "path";
|
|
1977
2230
|
import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
|
|
1978
2231
|
import chalk5 from "chalk";
|
|
1979
2232
|
import Table from "cli-table3";
|
|
1980
2233
|
async function installSkills(skillIds, tool, level, repoPath) {
|
|
1981
2234
|
const configRoot = getConfigRoot(tool, level);
|
|
1982
|
-
const skillsDir =
|
|
2235
|
+
const skillsDir = join13(configRoot, "skills");
|
|
1983
2236
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
1984
|
-
if (!
|
|
1985
|
-
|
|
2237
|
+
if (!existsSync13(skillsDir)) {
|
|
2238
|
+
mkdirSync6(skillsDir, { recursive: true });
|
|
1986
2239
|
}
|
|
1987
2240
|
const results = [];
|
|
1988
2241
|
const installedIds = [];
|
|
@@ -1993,17 +2246,17 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
1993
2246
|
continue;
|
|
1994
2247
|
}
|
|
1995
2248
|
const sourcePath = resolveSkillSourcePath(skill, repoPath);
|
|
1996
|
-
const targetPath =
|
|
1997
|
-
if (!
|
|
2249
|
+
const targetPath = join13(skillsDir, skillId);
|
|
2250
|
+
if (!existsSync13(sourcePath)) {
|
|
1998
2251
|
results.push({ skillId, success: false, error: t("error_source_not_found").replace("{path}", sourcePath) });
|
|
1999
2252
|
continue;
|
|
2000
2253
|
}
|
|
2001
2254
|
try {
|
|
2002
|
-
const resolvedSource =
|
|
2003
|
-
if (
|
|
2004
|
-
|
|
2255
|
+
const resolvedSource = realpathSync2(sourcePath);
|
|
2256
|
+
if (existsSync13(targetPath) || isSymlink(targetPath)) {
|
|
2257
|
+
unlinkSync5(targetPath);
|
|
2005
2258
|
}
|
|
2006
|
-
|
|
2259
|
+
symlinkSync2(resolvedSource, targetPath);
|
|
2007
2260
|
results.push({ skillId, success: true });
|
|
2008
2261
|
installedIds.push(skillId);
|
|
2009
2262
|
} catch (error) {
|
|
@@ -2021,15 +2274,15 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
2021
2274
|
}
|
|
2022
2275
|
async function uninstallSkills(skillIds, tool, level) {
|
|
2023
2276
|
const configRoot = getConfigRoot(tool, level);
|
|
2024
|
-
const skillsDir =
|
|
2277
|
+
const skillsDir = join13(configRoot, "skills");
|
|
2025
2278
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
2026
2279
|
const results = [];
|
|
2027
2280
|
const removedIds = [];
|
|
2028
2281
|
for (const skillId of skillIds) {
|
|
2029
|
-
const targetPath =
|
|
2282
|
+
const targetPath = join13(skillsDir, skillId);
|
|
2030
2283
|
try {
|
|
2031
|
-
if (
|
|
2032
|
-
|
|
2284
|
+
if (existsSync13(targetPath) || isSymlink(targetPath)) {
|
|
2285
|
+
unlinkSync5(targetPath);
|
|
2033
2286
|
results.push({ skillId, success: true });
|
|
2034
2287
|
removedIds.push(skillId);
|
|
2035
2288
|
logger.step(` ${t("uninstall_remove_label")}: ${skillId}`);
|
|
@@ -2044,7 +2297,7 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2044
2297
|
if (removedIds.length > 0) {
|
|
2045
2298
|
removeSkillsFromRecord(removedIds, tool, level, installPath);
|
|
2046
2299
|
}
|
|
2047
|
-
if (
|
|
2300
|
+
if (existsSync13(skillsDir)) {
|
|
2048
2301
|
try {
|
|
2049
2302
|
const entries = readdirSync4(skillsDir);
|
|
2050
2303
|
if (entries.length === 0) {
|
|
@@ -2227,12 +2480,12 @@ function listAllSkills() {
|
|
|
2227
2480
|
}
|
|
2228
2481
|
function resolveSkillSourcePath(skill, repoPath) {
|
|
2229
2482
|
if (skill.filePath) {
|
|
2230
|
-
const absPath = skill.filePath.startsWith("/") ? skill.filePath :
|
|
2231
|
-
if (
|
|
2232
|
-
return
|
|
2483
|
+
const absPath = skill.filePath.startsWith("/") ? skill.filePath : join13(repoPath, skill.filePath);
|
|
2484
|
+
if (existsSync13(absPath)) {
|
|
2485
|
+
return dirname7(absPath);
|
|
2233
2486
|
}
|
|
2234
2487
|
}
|
|
2235
|
-
return
|
|
2488
|
+
return join13(repoPath, skill.source, skill.id);
|
|
2236
2489
|
}
|
|
2237
2490
|
|
|
2238
2491
|
// src/ui/display.ts
|
|
@@ -2324,13 +2577,13 @@ function printEnhancedSummary(results, tool, configRoot) {
|
|
|
2324
2577
|
}
|
|
2325
2578
|
|
|
2326
2579
|
// src/commands/init.ts
|
|
2327
|
-
import { existsSync as
|
|
2328
|
-
import { join as
|
|
2580
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
|
|
2581
|
+
import { join as join14 } from "path";
|
|
2329
2582
|
async function initCommand() {
|
|
2330
2583
|
const cwd = process.cwd();
|
|
2331
|
-
if (
|
|
2584
|
+
if (existsSync14(join14(cwd, "package.json")) && (() => {
|
|
2332
2585
|
try {
|
|
2333
|
-
const pkg = JSON.parse(
|
|
2586
|
+
const pkg = JSON.parse(readFileSync9(join14(cwd, "package.json"), "utf-8"));
|
|
2334
2587
|
return pkg.name === "@cannbot-ai/install-helper";
|
|
2335
2588
|
} catch {
|
|
2336
2589
|
return false;
|
|
@@ -2555,8 +2808,8 @@ async function listCommand() {
|
|
|
2555
2808
|
|
|
2556
2809
|
// src/commands/doctor.ts
|
|
2557
2810
|
import chalk8 from "chalk";
|
|
2558
|
-
import { existsSync as
|
|
2559
|
-
import { join as
|
|
2811
|
+
import { existsSync as existsSync15, readdirSync as readdirSync5, lstatSync as lstatSync2, unlinkSync as unlinkSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
2812
|
+
import { join as join15 } from "path";
|
|
2560
2813
|
async function doctorCommand(options = {}) {
|
|
2561
2814
|
console.log();
|
|
2562
2815
|
console.log(chalk8.bold(` ${t("doctor_title")}`));
|
|
@@ -2598,7 +2851,7 @@ async function doctorCommand(options = {}) {
|
|
|
2598
2851
|
const configRoot = getConfigRoot(primaryTool, "project");
|
|
2599
2852
|
const skillsDir = getSkillsDir(configRoot);
|
|
2600
2853
|
const agentsDir = getAgentsDir(configRoot);
|
|
2601
|
-
if (
|
|
2854
|
+
if (existsSync15(skillsDir)) {
|
|
2602
2855
|
const brokenLinks = checkBrokenLinks(skillsDir);
|
|
2603
2856
|
if (brokenLinks === 0) {
|
|
2604
2857
|
const count = readdirSync5(skillsDir).length;
|
|
@@ -2615,12 +2868,12 @@ async function doctorCommand(options = {}) {
|
|
|
2615
2868
|
} else {
|
|
2616
2869
|
console.log(chalk8.dim(" \u2014") + ` ${skillsDir} \u2014 ${t("doctor_not_exist")}`);
|
|
2617
2870
|
if (options.fix) {
|
|
2618
|
-
|
|
2871
|
+
mkdirSync7(skillsDir, { recursive: true });
|
|
2619
2872
|
fixes++;
|
|
2620
2873
|
console.log(chalk8.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: ${t("doctor_created").replace("{path}", skillsDir)}`);
|
|
2621
2874
|
}
|
|
2622
2875
|
}
|
|
2623
|
-
if (
|
|
2876
|
+
if (existsSync15(agentsDir)) {
|
|
2624
2877
|
const brokenLinks = checkBrokenLinks(agentsDir);
|
|
2625
2878
|
if (brokenLinks === 0) {
|
|
2626
2879
|
const count = readdirSync5(agentsDir).length;
|
|
@@ -2637,7 +2890,7 @@ async function doctorCommand(options = {}) {
|
|
|
2637
2890
|
} else {
|
|
2638
2891
|
console.log(chalk8.dim(" \u2014") + ` ${agentsDir} \u2014 ${t("doctor_not_exist")}`);
|
|
2639
2892
|
if (options.fix) {
|
|
2640
|
-
|
|
2893
|
+
mkdirSync7(agentsDir, { recursive: true });
|
|
2641
2894
|
fixes++;
|
|
2642
2895
|
console.log(chalk8.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: ${t("doctor_created").replace("{path}", agentsDir)}`);
|
|
2643
2896
|
}
|
|
@@ -2645,8 +2898,8 @@ async function doctorCommand(options = {}) {
|
|
|
2645
2898
|
console.log();
|
|
2646
2899
|
console.log(chalk8.bold(` ${t("doctor_config")}`));
|
|
2647
2900
|
const configFile = getConfigFileName(primaryTool);
|
|
2648
|
-
const configPath =
|
|
2649
|
-
if (
|
|
2901
|
+
const configPath = join15(process.cwd(), configFile);
|
|
2902
|
+
if (existsSync15(configPath)) {
|
|
2650
2903
|
console.log(chalk8.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
|
|
2651
2904
|
} else {
|
|
2652
2905
|
console.log(chalk8.dim(" \u2014") + ` ${configFile} ${t("doctor_config_not_exist")}`);
|
|
@@ -2669,11 +2922,11 @@ function checkBrokenLinks(dir) {
|
|
|
2669
2922
|
try {
|
|
2670
2923
|
const entries = readdirSync5(dir);
|
|
2671
2924
|
for (const entry of entries) {
|
|
2672
|
-
const fullPath =
|
|
2925
|
+
const fullPath = join15(dir, entry);
|
|
2673
2926
|
try {
|
|
2674
2927
|
const stats = lstatSync2(fullPath);
|
|
2675
2928
|
if (stats.isSymbolicLink()) {
|
|
2676
|
-
if (!
|
|
2929
|
+
if (!existsSync15(fullPath)) {
|
|
2677
2930
|
broken++;
|
|
2678
2931
|
}
|
|
2679
2932
|
}
|
|
@@ -2690,12 +2943,12 @@ function fixBrokenLinks(dir) {
|
|
|
2690
2943
|
try {
|
|
2691
2944
|
const entries = readdirSync5(dir);
|
|
2692
2945
|
for (const entry of entries) {
|
|
2693
|
-
const fullPath =
|
|
2946
|
+
const fullPath = join15(dir, entry);
|
|
2694
2947
|
try {
|
|
2695
2948
|
const stats = lstatSync2(fullPath);
|
|
2696
2949
|
if (stats.isSymbolicLink()) {
|
|
2697
|
-
if (!
|
|
2698
|
-
|
|
2950
|
+
if (!existsSync15(fullPath)) {
|
|
2951
|
+
unlinkSync6(fullPath);
|
|
2699
2952
|
fixed++;
|
|
2700
2953
|
}
|
|
2701
2954
|
}
|
|
@@ -3040,8 +3293,8 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
|
|
|
3040
3293
|
}
|
|
3041
3294
|
|
|
3042
3295
|
// src/commands/uninstall.ts
|
|
3043
|
-
import { existsSync as
|
|
3044
|
-
import { resolve, basename } from "path";
|
|
3296
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync7, rmdirSync as rmdirSync2, readdirSync as readdirSync6 } from "fs";
|
|
3297
|
+
import { resolve, basename as basename2 } from "path";
|
|
3045
3298
|
import chalk11 from "chalk";
|
|
3046
3299
|
async function uninstallCommand(names, options) {
|
|
3047
3300
|
const tool = options.tool ? validateTool(options.tool) : "opencode";
|
|
@@ -3082,9 +3335,9 @@ async function uninstallCommand(names, options) {
|
|
|
3082
3335
|
for (const filePath of record.files) {
|
|
3083
3336
|
if (!isSafePath(filePath)) continue;
|
|
3084
3337
|
try {
|
|
3085
|
-
if (
|
|
3086
|
-
|
|
3087
|
-
const name =
|
|
3338
|
+
if (existsSync16(filePath) || isSymlink(filePath)) {
|
|
3339
|
+
unlinkSync7(filePath);
|
|
3340
|
+
const name = basename2(filePath);
|
|
3088
3341
|
logger.step(` ${t("uninstall_remove_label")}: ${name}`);
|
|
3089
3342
|
removedFiles++;
|
|
3090
3343
|
}
|
|
@@ -3097,11 +3350,11 @@ async function uninstallCommand(names, options) {
|
|
|
3097
3350
|
if (resolve(dirPath) === resolve(configRoot)) {
|
|
3098
3351
|
continue;
|
|
3099
3352
|
}
|
|
3100
|
-
if (
|
|
3353
|
+
if (existsSync16(dirPath)) {
|
|
3101
3354
|
const entries = readdirSync6(dirPath);
|
|
3102
3355
|
if (entries.length === 0) {
|
|
3103
3356
|
rmdirSync2(dirPath);
|
|
3104
|
-
const name =
|
|
3357
|
+
const name = basename2(dirPath);
|
|
3105
3358
|
logger.step(` ${t("uninstall_clean_empty_dir")}: ${name}/`);
|
|
3106
3359
|
removedDirs++;
|
|
3107
3360
|
}
|
|
@@ -3236,8 +3489,8 @@ async function updateCommand(pluginNames, options) {
|
|
|
3236
3489
|
|
|
3237
3490
|
// src/commands/info.ts
|
|
3238
3491
|
import chalk13 from "chalk";
|
|
3239
|
-
import { existsSync as
|
|
3240
|
-
import { join as
|
|
3492
|
+
import { existsSync as existsSync17, readdirSync as readdirSync7 } from "fs";
|
|
3493
|
+
import { join as join16 } from "path";
|
|
3241
3494
|
async function infoCommand(pluginName) {
|
|
3242
3495
|
const plugin = findPlugin(pluginName);
|
|
3243
3496
|
if (!plugin) {
|
|
@@ -3262,12 +3515,12 @@ async function infoCommand(pluginName) {
|
|
|
3262
3515
|
try {
|
|
3263
3516
|
const repoManager = createRepositoryManager();
|
|
3264
3517
|
const repoPath = await repoManager.ensureRepo();
|
|
3265
|
-
const quickstartPath =
|
|
3266
|
-
if (
|
|
3518
|
+
const quickstartPath = join16(repoPath, plugin.dir, "quickstart.md");
|
|
3519
|
+
if (existsSync17(quickstartPath)) {
|
|
3267
3520
|
console.log(` ${chalk13.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
|
|
3268
3521
|
}
|
|
3269
|
-
const agentsDir =
|
|
3270
|
-
if (
|
|
3522
|
+
const agentsDir = join16(repoPath, plugin.dir, "agents");
|
|
3523
|
+
if (existsSync17(agentsDir)) {
|
|
3271
3524
|
const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
|
|
3272
3525
|
if (agentFiles.length > 0) {
|
|
3273
3526
|
console.log();
|
|
@@ -3319,15 +3572,15 @@ async function langCommand(action, value) {
|
|
|
3319
3572
|
}
|
|
3320
3573
|
|
|
3321
3574
|
// src/cli.ts
|
|
3322
|
-
import { readFileSync as
|
|
3575
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
3323
3576
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
3324
|
-
import { dirname as
|
|
3577
|
+
import { dirname as dirname8, join as join17 } from "path";
|
|
3325
3578
|
function readVersion() {
|
|
3326
3579
|
try {
|
|
3327
3580
|
const __filename5 = fileURLToPath5(import.meta.url);
|
|
3328
|
-
const __dirname5 =
|
|
3329
|
-
const pkgPath =
|
|
3330
|
-
const pkg = JSON.parse(
|
|
3581
|
+
const __dirname5 = dirname8(__filename5);
|
|
3582
|
+
const pkgPath = join17(__dirname5, "..", "package.json");
|
|
3583
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
3331
3584
|
return pkg.version || "0.0.0";
|
|
3332
3585
|
} catch {
|
|
3333
3586
|
return "0.0.0";
|