@cannbot-ai/install-helper 1.2.1-beta.2 → 1.2.2-beta.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/README.md +10 -13
- package/dist/index.js +336 -140
- package/dist/index.js.map +1 -1
- package/dist/locales/en_US.json +10 -0
- package/dist/locales/zh_CN.json +10 -0
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -177,6 +177,15 @@ var init_zh_CN = __esm({
|
|
|
177
177
|
backup_restore_success: "\u5DF2\u6062\u590D\u914D\u7F6E",
|
|
178
178
|
backup_created: "\u5DF2\u521B\u5EFA\u5907\u4EFD",
|
|
179
179
|
backup_failed: "\u5907\u4EFD\u521B\u5EFA\u5931\u8D25\uFF0C\u5B89\u88C5\u5DF2\u4E2D\u6B62\u4EE5\u4FDD\u62A4\u73B0\u6709\u914D\u7F6E",
|
|
180
|
+
unowned_file_detected: "\u68C0\u6D4B\u5230\u975E CANNBot \u5B89\u88C5\u7684\u914D\u7F6E\u6587\u4EF6",
|
|
181
|
+
unowned_file_path: "\u6587\u4EF6",
|
|
182
|
+
unowned_file_warning: "\u8BE5\u6587\u4EF6\u4E0D\u662F\u7531 CANNBot \u5B89\u88C5\u7684\u3002\u66FF\u6362\u5C06\u8986\u76D6\u5176\u73B0\u6709\u5185\u5BB9\uFF08\u4F1A\u5728\u6587\u4EF6\u65C1\u521B\u5EFA\u5907\u4EFD\uFF09\u3002",
|
|
183
|
+
unowned_file_keep: "\u4FDD\u7559\u6211\u7684\u6587\u4EF6\uFF08\u8DF3\u8FC7\u66FF\u6362\uFF09",
|
|
184
|
+
unowned_file_replace: "\u66FF\u6362\uFF08\u81EA\u52A8\u5907\u4EFD\uFF09",
|
|
185
|
+
unowned_preserved: "\u5DF2\u4FDD\u7559\u73B0\u6709\u6587\u4EF6\uFF08\u672A\u66FF\u6362\uFF09: {file}",
|
|
186
|
+
unowned_preserved_yes: "\u975E\u4EA4\u4E92\u6A21\u5F0F\uFF1A\u5DF2\u4FDD\u7559\u975E CANNBot \u5B89\u88C5\u7684\u73B0\u6709\u6587\u4EF6: {file}",
|
|
187
|
+
unowned_backup_label: "\u7528\u6237\u6587\u4EF6",
|
|
188
|
+
backup_restore_user_file: "\u6062\u590D\u7528\u6237\u6587\u4EF6",
|
|
180
189
|
loading_skills_list: "\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...",
|
|
181
190
|
loading_skills_list_complete: "Skills \u5217\u8868\u52A0\u8F7D\u5B8C\u6210",
|
|
182
191
|
loading_plugin_data: "\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u6570\u636E...",
|
|
@@ -191,6 +200,7 @@ var init_zh_CN = __esm({
|
|
|
191
200
|
skill_record_corrupted: "Skill \u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
|
|
192
201
|
record_write_failed: "\u5B89\u88C5\u8BB0\u5F55\u5199\u5165\u5931\u8D25\uFF0C\u5378\u8F7D\u65F6\u53EF\u80FD\u65E0\u6CD5\u81EA\u52A8\u6E05\u7406",
|
|
193
202
|
install_config_failed: "\u914D\u7F6E\u6587\u4EF6\u5B89\u88C5\u5931\u8D25: {error}",
|
|
203
|
+
install_config_preserved: "\u5DF2\u8DF3\u8FC7\u914D\u7F6E\u6587\u4EF6\uFF08\u4FDD\u7559\u73B0\u6709\u6587\u4EF6\uFF09: {file}",
|
|
194
204
|
install_clone_failed: "git clone \u5931\u8D25: {url}\uFF0C\u8BF7\u624B\u52A8\u514B\u9686: git clone {url} {dir}",
|
|
195
205
|
install_link_config_failed: "\u94FE\u63A5 {name} \u5230\u914D\u7F6E\u76EE\u5F55\u5931\u8D25",
|
|
196
206
|
install_link_project_failed: "\u94FE\u63A5 {name} \u5230\u9879\u76EE\u76EE\u5F55\u5931\u8D25",
|
|
@@ -429,6 +439,15 @@ var init_en_US = __esm({
|
|
|
429
439
|
backup_restore_success: "Configuration restored",
|
|
430
440
|
backup_created: "Backup created",
|
|
431
441
|
backup_failed: "Backup creation failed, installation aborted to protect existing config",
|
|
442
|
+
unowned_file_detected: "Configuration file not created by CANNBot detected",
|
|
443
|
+
unowned_file_path: "File",
|
|
444
|
+
unowned_file_warning: "This file was not installed by CANNBot. Replacing it overwrites its current content (a backup is created beside it).",
|
|
445
|
+
unowned_file_keep: "Keep my file (skip replacing it)",
|
|
446
|
+
unowned_file_replace: "Replace (auto backup)",
|
|
447
|
+
unowned_preserved: "Kept existing file (not replaced): {file}",
|
|
448
|
+
unowned_preserved_yes: "Non-interactive mode: kept existing file not created by CANNBot: {file}",
|
|
449
|
+
unowned_backup_label: "User file",
|
|
450
|
+
backup_restore_user_file: "Restore user file",
|
|
432
451
|
loading_skills_list: "Loading Skills list...",
|
|
433
452
|
loading_skills_list_complete: "Skills list loaded",
|
|
434
453
|
loading_plugin_data: "Loading plugin data...",
|
|
@@ -443,6 +462,7 @@ var init_en_US = __esm({
|
|
|
443
462
|
skill_record_corrupted: "Skill install record corrupted",
|
|
444
463
|
record_write_failed: "Install record write failed, uninstall may not work properly",
|
|
445
464
|
install_config_failed: "Failed to install config file: {error}",
|
|
465
|
+
install_config_preserved: "Skipped config file (kept existing file): {file}",
|
|
446
466
|
install_clone_failed: "git clone failed: {url}, clone manually: git clone {url} {dir}",
|
|
447
467
|
install_link_config_failed: "Failed to link {name} to config directory",
|
|
448
468
|
install_link_project_failed: "Failed to link {name} to project directory",
|
|
@@ -1356,10 +1376,10 @@ var init_embedded_plugins = __esm({
|
|
|
1356
1376
|
aliases: [
|
|
1357
1377
|
"tilelang"
|
|
1358
1378
|
],
|
|
1359
|
-
skills:
|
|
1360
|
-
agents:
|
|
1379
|
+
skills: 13,
|
|
1380
|
+
agents: 6,
|
|
1361
1381
|
description: "TileLang Python DSL + @tilelang.jit \u7B97\u5B50\u5F00\u53D1\uFF08\u652F\u6301 Developer/Expert \u53CC\u6A21\u5F0F\uFF09",
|
|
1362
|
-
version: "1.
|
|
1382
|
+
version: "1.2.0",
|
|
1363
1383
|
configFile: "AGENTS.md",
|
|
1364
1384
|
configRootConfigLink: false,
|
|
1365
1385
|
installSkills: [
|
|
@@ -1374,14 +1394,21 @@ var init_embedded_plugins = __esm({
|
|
|
1374
1394
|
"tilelang-perf-optimization",
|
|
1375
1395
|
"tilelang-programming-model-guide",
|
|
1376
1396
|
"tilelang-review",
|
|
1377
|
-
"tilelang-submodule-pull"
|
|
1397
|
+
"tilelang-submodule-pull",
|
|
1398
|
+
"tilelang-performance-best-practices",
|
|
1399
|
+
"ascendc-env-check",
|
|
1400
|
+
"npu-arch",
|
|
1401
|
+
"tilelang-op-profiling"
|
|
1378
1402
|
]
|
|
1379
1403
|
}
|
|
1380
1404
|
],
|
|
1381
1405
|
installAgents: [
|
|
1382
1406
|
"tilelang-op-analyst",
|
|
1383
1407
|
"tilelang-op-developer",
|
|
1384
|
-
"tilelang-op-perf-tuner"
|
|
1408
|
+
"tilelang-op-perf-tuner",
|
|
1409
|
+
"tilelang-tuning",
|
|
1410
|
+
"tilelang-perf-analysis-expert",
|
|
1411
|
+
"tilelang-perf-impl-expert"
|
|
1385
1412
|
],
|
|
1386
1413
|
externalRepos: [
|
|
1387
1414
|
{
|
|
@@ -2913,7 +2940,7 @@ function createRepositoryManager(customPath) {
|
|
|
2913
2940
|
|
|
2914
2941
|
// src/core/cannbot-delegate.ts
|
|
2915
2942
|
import { existsSync as existsSync17, readFileSync as readFileSync12, writeFileSync as writeFileSync5, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6, readdirSync as readdirSync8 } from "fs";
|
|
2916
|
-
import { join as join16, resolve as
|
|
2943
|
+
import { join as join16, resolve as resolve4 } from "path";
|
|
2917
2944
|
import { execa as execa6 } from "execa";
|
|
2918
2945
|
|
|
2919
2946
|
// src/core/cannbot-installer.ts
|
|
@@ -3247,7 +3274,7 @@ function deleteRecord(pluginId, where) {
|
|
|
3247
3274
|
writeStore(pluginId, store);
|
|
3248
3275
|
}
|
|
3249
3276
|
}
|
|
3250
|
-
function scanInstalledFiles(pluginId, displayName, tool, level, installPath, configRoot, manifest, externalRepoNames, configRootConfigLink) {
|
|
3277
|
+
function scanInstalledFiles(pluginId, displayName, tool, level, installPath, configRoot, manifest, externalRepoNames, configRootConfigLink, preservedTargets) {
|
|
3251
3278
|
const files = [];
|
|
3252
3279
|
const directories = [];
|
|
3253
3280
|
if (manifest) {
|
|
@@ -3289,12 +3316,12 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
3289
3316
|
}
|
|
3290
3317
|
const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
3291
3318
|
const configFilePath = level === "project" ? join11(installPath, configFileName) : join11(configRoot, configFileName);
|
|
3292
|
-
if (existsSync12(configFilePath) || isSymlink(configFilePath)) {
|
|
3319
|
+
if (!preservedTargets?.includes(configFilePath) && (existsSync12(configFilePath) || isSymlink(configFilePath))) {
|
|
3293
3320
|
files.push(configFilePath);
|
|
3294
3321
|
}
|
|
3295
3322
|
if (level === "project" && configRootConfigLink !== false) {
|
|
3296
3323
|
const configRootConfigPath = join11(configRoot, configFileName);
|
|
3297
|
-
if (configRootConfigPath !== configFilePath && (existsSync12(configRootConfigPath) || isSymlink(configRootConfigPath))) {
|
|
3324
|
+
if (configRootConfigPath !== configFilePath && !preservedTargets?.includes(configRootConfigPath) && (existsSync12(configRootConfigPath) || isSymlink(configRootConfigPath))) {
|
|
3298
3325
|
files.push(configRootConfigPath);
|
|
3299
3326
|
}
|
|
3300
3327
|
}
|
|
@@ -3813,16 +3840,17 @@ function findOrphanedDelegatedRecords(target) {
|
|
|
3813
3840
|
init_registry();
|
|
3814
3841
|
init_manifest();
|
|
3815
3842
|
init_paths();
|
|
3816
|
-
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
|
|
3817
|
-
import { join as join15, basename as
|
|
3843
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, realpathSync as realpathSync2 } from "fs";
|
|
3844
|
+
import { join as join15, basename as basename3, isAbsolute } from "path";
|
|
3818
3845
|
import { execa as execa5, execaSync as execaSync2 } from "execa";
|
|
3819
3846
|
|
|
3820
3847
|
// src/core/backup.ts
|
|
3821
3848
|
init_manifest();
|
|
3822
3849
|
import { existsSync as existsSync14, copyFileSync, readdirSync as readdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
3823
|
-
import { join as join13 } from "path";
|
|
3850
|
+
import { join as join13, dirname as dirname7, basename, resolve as resolve3 } from "path";
|
|
3824
3851
|
init_registry();
|
|
3825
3852
|
init_paths();
|
|
3853
|
+
var UNOWNED_PLUGIN_ID = "unowned";
|
|
3826
3854
|
function detectCurrentPlugin(configRoot, tool, installPath) {
|
|
3827
3855
|
const manifests = readAllManifests(configRoot);
|
|
3828
3856
|
if (manifests.length > 0) {
|
|
@@ -3860,18 +3888,18 @@ function detectCurrentPlugin(configRoot, tool, installPath) {
|
|
|
3860
3888
|
}
|
|
3861
3889
|
return null;
|
|
3862
3890
|
}
|
|
3863
|
-
function createBackup(
|
|
3864
|
-
|
|
3865
|
-
if (!existsSync14(agentsFile)) {
|
|
3891
|
+
function createBackup(targetPath, fromPluginId, fromPluginName) {
|
|
3892
|
+
if (!existsSync14(targetPath)) {
|
|
3866
3893
|
return null;
|
|
3867
3894
|
}
|
|
3868
3895
|
const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
|
|
3869
|
-
const backupFileName = `${
|
|
3870
|
-
const backupPath = join13(
|
|
3896
|
+
const backupFileName = `${basename(targetPath)}.cannbot-backup.${fromPluginId}.${timestamp}`;
|
|
3897
|
+
const backupPath = join13(dirname7(targetPath), backupFileName);
|
|
3871
3898
|
try {
|
|
3872
|
-
copyFileSync(
|
|
3899
|
+
copyFileSync(targetPath, backupPath);
|
|
3873
3900
|
return {
|
|
3874
3901
|
filePath: backupPath,
|
|
3902
|
+
originalPath: targetPath,
|
|
3875
3903
|
pluginId: fromPluginId,
|
|
3876
3904
|
pluginName: fromPluginName,
|
|
3877
3905
|
backupTime: timestamp
|
|
@@ -3880,38 +3908,54 @@ function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
|
3880
3908
|
return null;
|
|
3881
3909
|
}
|
|
3882
3910
|
}
|
|
3883
|
-
function
|
|
3884
|
-
|
|
3885
|
-
|
|
3911
|
+
function findRecordOwner(targetPath) {
|
|
3912
|
+
const resolved = resolve3(targetPath);
|
|
3913
|
+
for (const record of readAllRecords()) {
|
|
3914
|
+
if ((record.files || []).some((f) => resolve3(f) === resolved)) {
|
|
3915
|
+
const plugin = findPlugin(record.pluginId);
|
|
3916
|
+
return {
|
|
3917
|
+
pluginId: record.pluginId,
|
|
3918
|
+
pluginName: plugin?.displayName || record.displayName || record.pluginId
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3886
3921
|
}
|
|
3887
|
-
|
|
3922
|
+
return null;
|
|
3923
|
+
}
|
|
3924
|
+
function findBackups(configRoot) {
|
|
3925
|
+
const dirs = Array.isArray(configRoot) ? configRoot : [configRoot];
|
|
3888
3926
|
const backups = [];
|
|
3889
|
-
for (const
|
|
3890
|
-
if (
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
const
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
pluginId,
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3927
|
+
for (const dir of dirs) {
|
|
3928
|
+
if (!existsSync14(dir)) {
|
|
3929
|
+
continue;
|
|
3930
|
+
}
|
|
3931
|
+
const files = readdirSync7(dir);
|
|
3932
|
+
for (const file of files) {
|
|
3933
|
+
if (file.includes(".cannbot-backup.")) {
|
|
3934
|
+
const parts = file.split(".cannbot-backup.");
|
|
3935
|
+
if (parts.length === 2) {
|
|
3936
|
+
const pluginIdAndTime = parts[1];
|
|
3937
|
+
const lastDotIndex = pluginIdAndTime.lastIndexOf(".");
|
|
3938
|
+
if (lastDotIndex > 0) {
|
|
3939
|
+
const pluginId = pluginIdAndTime.substring(0, lastDotIndex);
|
|
3940
|
+
const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
|
|
3941
|
+
const plugin = findPlugin(pluginId);
|
|
3942
|
+
backups.push({
|
|
3943
|
+
filePath: join13(dir, file),
|
|
3944
|
+
originalPath: join13(dir, parts[0]),
|
|
3945
|
+
pluginId,
|
|
3946
|
+
pluginName: plugin?.displayName || pluginId,
|
|
3947
|
+
backupTime: timestamp
|
|
3948
|
+
});
|
|
3949
|
+
}
|
|
3905
3950
|
}
|
|
3906
3951
|
}
|
|
3907
3952
|
}
|
|
3908
3953
|
}
|
|
3909
3954
|
return backups.sort((a, b) => b.backupTime.localeCompare(a.backupTime));
|
|
3910
3955
|
}
|
|
3911
|
-
function restoreBackup(backupPath,
|
|
3956
|
+
function restoreBackup(backupPath, targetPath) {
|
|
3912
3957
|
try {
|
|
3913
|
-
|
|
3914
|
-
copyFileSync(backupPath, agentsFile);
|
|
3958
|
+
copyFileSync(backupPath, targetPath);
|
|
3915
3959
|
return true;
|
|
3916
3960
|
} catch {
|
|
3917
3961
|
return false;
|
|
@@ -3939,13 +3983,21 @@ function formatTimestamp(date) {
|
|
|
3939
3983
|
}
|
|
3940
3984
|
function readAllRecords() {
|
|
3941
3985
|
const records = [];
|
|
3942
|
-
const
|
|
3943
|
-
|
|
3944
|
-
records
|
|
3986
|
+
const installsDir = join13(getCannbotConfigDir(), "installs");
|
|
3987
|
+
if (!existsSync14(installsDir)) {
|
|
3988
|
+
return records;
|
|
3989
|
+
}
|
|
3990
|
+
for (const file of readdirSync7(installsDir)) {
|
|
3991
|
+
if (!file.endsWith(".json") || file === "skills.json") continue;
|
|
3992
|
+
const pluginId = file.replace(/\.json$/, "");
|
|
3993
|
+
records.push(...readRecords(pluginId));
|
|
3945
3994
|
}
|
|
3946
3995
|
return records;
|
|
3947
3996
|
}
|
|
3948
3997
|
|
|
3998
|
+
// src/core/installer.ts
|
|
3999
|
+
init_fs_helpers();
|
|
4000
|
+
|
|
3949
4001
|
// src/ui/backup-prompts.ts
|
|
3950
4002
|
init_i18n();
|
|
3951
4003
|
import { select as select2 } from "@inquirer/prompts";
|
|
@@ -3969,12 +4021,31 @@ async function showOverwriteWarning(currentPluginName, newPluginName) {
|
|
|
3969
4021
|
});
|
|
3970
4022
|
return choice;
|
|
3971
4023
|
}
|
|
4024
|
+
async function showUnownedFileWarning(filePath, newPluginName) {
|
|
4025
|
+
console.log();
|
|
4026
|
+
console.log(chalk4.yellow(` \u26A0\uFE0F ${t("unowned_file_detected")}`));
|
|
4027
|
+
console.log();
|
|
4028
|
+
console.log(` ${t("unowned_file_path")}: ${chalk4.cyan(filePath)}`);
|
|
4029
|
+
console.log(` ${t("backup_installing")}: ${chalk4.cyan(newPluginName)}`);
|
|
4030
|
+
console.log();
|
|
4031
|
+
console.log(` ${t("unowned_file_warning")}`);
|
|
4032
|
+
console.log();
|
|
4033
|
+
const choice = await select2({
|
|
4034
|
+
message: t("backup_select_action"),
|
|
4035
|
+
choices: [
|
|
4036
|
+
{ name: t("unowned_file_keep"), value: "keep" },
|
|
4037
|
+
{ name: t("unowned_file_replace"), value: "replace" },
|
|
4038
|
+
{ name: t("backup_cancel"), value: "cancel" }
|
|
4039
|
+
]
|
|
4040
|
+
});
|
|
4041
|
+
return choice;
|
|
4042
|
+
}
|
|
3972
4043
|
async function showRestorePrompt(backups) {
|
|
3973
4044
|
console.log();
|
|
3974
4045
|
console.log(chalk4.cyan(` ${t("backup_restore_prompt")}`));
|
|
3975
4046
|
console.log();
|
|
3976
4047
|
const choices = backups.map((b) => ({
|
|
3977
|
-
name: `${t("backup_restore")} ${b.pluginName} (${b.backupTime})`,
|
|
4048
|
+
name: b.pluginId === "unowned" ? `${t("backup_restore_user_file")} ${b.originalPath} (${b.backupTime})` : `${t("backup_restore")} ${b.pluginName} (${b.backupTime})`,
|
|
3978
4049
|
value: b.filePath
|
|
3979
4050
|
}));
|
|
3980
4051
|
choices.push({ name: t("backup_only_uninstall"), value: "none" });
|
|
@@ -3991,7 +4062,7 @@ init_fs_helpers();
|
|
|
3991
4062
|
init_logger();
|
|
3992
4063
|
init_i18n();
|
|
3993
4064
|
import { existsSync as existsSync15, mkdirSync as mkdirSync6, symlinkSync, realpathSync, readlinkSync, copyFileSync as copyFileSync2, cpSync, writeFileSync as writeFileSync4, rmSync as rmSync4, readFileSync as readFileSync10, constants as fsConstants } from "fs";
|
|
3994
|
-
import { join as join14, basename } from "path";
|
|
4065
|
+
import { join as join14, basename as basename2 } from "path";
|
|
3995
4066
|
import { execa as execa4 } from "execa";
|
|
3996
4067
|
var ISSUE_HANDLER_ID = "gitcode-issue-handler";
|
|
3997
4068
|
var ISSUE_HANDLER_CONFIG_FILES = ["classify_config.yaml", "operator_owners.yaml"];
|
|
@@ -4058,7 +4129,25 @@ function installLink(source, target) {
|
|
|
4058
4129
|
return "failed";
|
|
4059
4130
|
}
|
|
4060
4131
|
}
|
|
4061
|
-
function
|
|
4132
|
+
function configFileTargets(pluginDir, configFile, tool, level, configRoot, installPath, configRootConfigLink) {
|
|
4133
|
+
const sourcePath = join14(pluginDir, configFile);
|
|
4134
|
+
if (!existsSync15(sourcePath)) return [];
|
|
4135
|
+
const agentsFileName = getAgentsFileName(tool);
|
|
4136
|
+
const targets = [];
|
|
4137
|
+
if (level === "project") {
|
|
4138
|
+
targets.push(join14(installPath, agentsFileName));
|
|
4139
|
+
if (configRootConfigLink !== false) {
|
|
4140
|
+
const configRootTarget = join14(configRoot, agentsFileName);
|
|
4141
|
+
if (!targets.includes(configRootTarget)) {
|
|
4142
|
+
targets.push(configRootTarget);
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
} else {
|
|
4146
|
+
targets.push(join14(configRoot, agentsFileName));
|
|
4147
|
+
}
|
|
4148
|
+
return targets;
|
|
4149
|
+
}
|
|
4150
|
+
function installConfigFile(pluginDir, configFile, tool, level, configRoot, installPath, configRootConfigLink, preservedTargets) {
|
|
4062
4151
|
const sourcePath = join14(pluginDir, configFile);
|
|
4063
4152
|
if (!existsSync15(sourcePath)) return;
|
|
4064
4153
|
const agentsFileName = getAgentsFileName(tool);
|
|
@@ -4069,26 +4158,34 @@ function installConfigFile(pluginDir, configFile, tool, level, configRoot, insta
|
|
|
4069
4158
|
} else {
|
|
4070
4159
|
primaryTarget = join14(configRoot, agentsFileName);
|
|
4071
4160
|
}
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
removePath(primaryTarget);
|
|
4076
|
-
}
|
|
4161
|
+
if (preservedTargets?.includes(primaryTarget)) {
|
|
4162
|
+
logger.info(t("install_config_preserved").replace("{file}", primaryTarget));
|
|
4163
|
+
} else {
|
|
4077
4164
|
try {
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
copyFileSync2(sourcePath, primaryTarget);
|
|
4082
|
-
} else {
|
|
4083
|
-
throw e;
|
|
4165
|
+
const resolvedSource = realpathSync(sourcePath);
|
|
4166
|
+
if (existsSync15(primaryTarget) || isSymlink(primaryTarget)) {
|
|
4167
|
+
removePath(primaryTarget);
|
|
4084
4168
|
}
|
|
4169
|
+
try {
|
|
4170
|
+
symlinkSync(resolvedSource, primaryTarget);
|
|
4171
|
+
} catch (e) {
|
|
4172
|
+
if (e.code === "EPERM") {
|
|
4173
|
+
copyFileSync2(sourcePath, primaryTarget);
|
|
4174
|
+
} else {
|
|
4175
|
+
throw e;
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
} catch (e) {
|
|
4179
|
+
logger.warn(t("install_config_failed").replace("{error}", e.message));
|
|
4085
4180
|
}
|
|
4086
|
-
} catch (e) {
|
|
4087
|
-
logger.warn(t("install_config_failed").replace("{error}", e.message));
|
|
4088
4181
|
}
|
|
4089
4182
|
if (isProjectLevel && primaryTarget !== join14(configRoot, agentsFileName)) {
|
|
4090
4183
|
if (configRootConfigLink === false) return;
|
|
4091
4184
|
const configRootTarget = join14(configRoot, agentsFileName);
|
|
4185
|
+
if (preservedTargets?.includes(configRootTarget)) {
|
|
4186
|
+
logger.info(t("install_config_preserved").replace("{file}", configRootTarget));
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4092
4189
|
if (existsSync15(configRootTarget) || isSymlink(configRootTarget)) {
|
|
4093
4190
|
removePath(configRootTarget);
|
|
4094
4191
|
}
|
|
@@ -4132,7 +4229,7 @@ async function installExternalRepos(repos, repoPath, configRoot, installPath, le
|
|
|
4132
4229
|
continue;
|
|
4133
4230
|
}
|
|
4134
4231
|
}
|
|
4135
|
-
const linkName =
|
|
4232
|
+
const linkName = basename2(repo.dir);
|
|
4136
4233
|
const resolved = realpathSync(targetDir);
|
|
4137
4234
|
const shouldConfigRootLink = repo.configRootLink !== false && (level === "global" || repo.configRootLink === true);
|
|
4138
4235
|
if (shouldConfigRootLink) {
|
|
@@ -4207,7 +4304,7 @@ function writeCannbotManifest(configRoot, pluginId, version, level, tool, skills
|
|
|
4207
4304
|
writeFileSync4(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
4208
4305
|
return manifest;
|
|
4209
4306
|
}
|
|
4210
|
-
async function installViaManifest(plugin, repoPath, tool, level, installPath) {
|
|
4307
|
+
async function installViaManifest(plugin, repoPath, tool, level, installPath, preservedTargets) {
|
|
4211
4308
|
const cwd = installPath || process.cwd();
|
|
4212
4309
|
const configRoot = getConfigRoot(tool, level, installPath);
|
|
4213
4310
|
const pluginDir = join14(repoPath, plugin.dir);
|
|
@@ -4278,7 +4375,7 @@ async function installViaManifest(plugin, repoPath, tool, level, installPath) {
|
|
|
4278
4375
|
logger.warn(t("install_agent_failed").replace("{name}", agentFile));
|
|
4279
4376
|
}
|
|
4280
4377
|
}
|
|
4281
|
-
installConfigFile(pluginDir, plugin.configFile || "AGENTS.md", tool, level, configRoot, cwd, plugin.configRootConfigLink);
|
|
4378
|
+
installConfigFile(pluginDir, plugin.configFile || "AGENTS.md", tool, level, configRoot, cwd, plugin.configRootConfigLink, preservedTargets);
|
|
4282
4379
|
installWorkflows(pluginDir, configRoot);
|
|
4283
4380
|
await installExternalRepos(plugin.externalRepos, repoPath, configRoot, cwd, level);
|
|
4284
4381
|
const cannbotManifest = writeCannbotManifest(
|
|
@@ -4334,6 +4431,25 @@ function scriptSupportsTool(scriptPath, tool) {
|
|
|
4334
4431
|
return true;
|
|
4335
4432
|
}
|
|
4336
4433
|
}
|
|
4434
|
+
function classifyConfigTarget(targetPath, pluginConfigSource, pluginId, pluginName, configRoot, tool, installPath) {
|
|
4435
|
+
if (isSymlink(targetPath)) {
|
|
4436
|
+
try {
|
|
4437
|
+
if (realpathSync2(targetPath) === realpathSync2(pluginConfigSource)) {
|
|
4438
|
+
return { kind: "same-plugin", pluginId, pluginName };
|
|
4439
|
+
}
|
|
4440
|
+
} catch {
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
const recordOwner = findRecordOwner(targetPath);
|
|
4444
|
+
if (recordOwner) {
|
|
4445
|
+
return recordOwner.pluginId === pluginId ? { kind: "same-plugin", pluginId, pluginName } : { kind: "other-plugin", ...recordOwner };
|
|
4446
|
+
}
|
|
4447
|
+
const currentPlugin = detectCurrentPlugin(configRoot, tool, installPath);
|
|
4448
|
+
if (currentPlugin) {
|
|
4449
|
+
return currentPlugin.pluginId === pluginId ? { kind: "same-plugin", pluginId, pluginName } : { kind: "other-plugin", ...currentPlugin };
|
|
4450
|
+
}
|
|
4451
|
+
return { kind: "unowned", pluginId: UNOWNED_PLUGIN_ID, pluginName: UNOWNED_PLUGIN_ID };
|
|
4452
|
+
}
|
|
4337
4453
|
async function installPlugin(opts) {
|
|
4338
4454
|
const plugin = opts.plugin ?? getPluginById(opts.pluginId);
|
|
4339
4455
|
if (!plugin) {
|
|
@@ -4359,38 +4475,55 @@ async function installPlugin(opts) {
|
|
|
4359
4475
|
const pluginDir = isAbsolute(plugin.dir) ? plugin.dir : join15(opts.repoPath, plugin.dir);
|
|
4360
4476
|
const cwd = opts.installPath || process.cwd();
|
|
4361
4477
|
const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
|
|
4362
|
-
const
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4478
|
+
const pluginConfigSource = join15(pluginDir, plugin.configFile || "AGENTS.md");
|
|
4479
|
+
const existingTargets = configFileTargets(
|
|
4480
|
+
pluginDir,
|
|
4481
|
+
plugin.configFile || "AGENTS.md",
|
|
4482
|
+
opts.tool,
|
|
4483
|
+
opts.level,
|
|
4484
|
+
configRoot,
|
|
4485
|
+
cwd,
|
|
4486
|
+
plugin.configRootConfigLink
|
|
4487
|
+
).filter((p) => existsSync16(p) || isSymlink(p));
|
|
4488
|
+
const backups = [];
|
|
4489
|
+
const preservedTargets = [];
|
|
4490
|
+
const promptedPlugins = /* @__PURE__ */ new Set();
|
|
4491
|
+
for (const target of existingTargets) {
|
|
4492
|
+
const owner = classifyConfigTarget(
|
|
4493
|
+
target,
|
|
4494
|
+
pluginConfigSource,
|
|
4495
|
+
opts.pluginId,
|
|
4496
|
+
plugin.displayName,
|
|
4497
|
+
configRoot,
|
|
4498
|
+
opts.tool,
|
|
4499
|
+
cwd
|
|
4500
|
+
);
|
|
4501
|
+
if (owner.kind === "same-plugin") {
|
|
4502
|
+
const backup2 = createBackup(target, owner.pluginId, owner.pluginName);
|
|
4503
|
+
if (backup2) backups.push(backup2);
|
|
4504
|
+
continue;
|
|
4385
4505
|
}
|
|
4386
|
-
if (
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4506
|
+
if (owner.kind === "other-plugin") {
|
|
4507
|
+
if (!promptedPlugins.has(owner.pluginId)) {
|
|
4508
|
+
promptedPlugins.add(owner.pluginId);
|
|
4509
|
+
let choice2 = "overwrite";
|
|
4510
|
+
if (!opts.yes) {
|
|
4511
|
+
choice2 = await showOverwriteWarning(owner.pluginName, plugin.displayName);
|
|
4512
|
+
}
|
|
4513
|
+
if (choice2 === "cancel") {
|
|
4514
|
+
logger.info(t("backup_cancel"));
|
|
4515
|
+
return {
|
|
4516
|
+
success: false,
|
|
4517
|
+
pluginId: opts.pluginId,
|
|
4518
|
+
skillsCount: 0,
|
|
4519
|
+
agentsCount: 0,
|
|
4520
|
+
errors: [t("backup_cancel")],
|
|
4521
|
+
warnings: []
|
|
4522
|
+
};
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
const backup2 = createBackup(target, owner.pluginId, owner.pluginName);
|
|
4526
|
+
if (!backup2) {
|
|
4394
4527
|
logger.error(t("backup_failed"));
|
|
4395
4528
|
return {
|
|
4396
4529
|
success: false,
|
|
@@ -4401,8 +4534,46 @@ async function installPlugin(opts) {
|
|
|
4401
4534
|
warnings: []
|
|
4402
4535
|
};
|
|
4403
4536
|
}
|
|
4404
|
-
|
|
4537
|
+
backups.push(backup2);
|
|
4538
|
+
logger.success(`${t("backup_created")}: ${backup2.filePath}`);
|
|
4539
|
+
continue;
|
|
4540
|
+
}
|
|
4541
|
+
if (opts.yes) {
|
|
4542
|
+
preservedTargets.push(target);
|
|
4543
|
+
logger.warn(t("unowned_preserved_yes").replace("{file}", target));
|
|
4544
|
+
continue;
|
|
4545
|
+
}
|
|
4546
|
+
const choice = await showUnownedFileWarning(target, plugin.displayName);
|
|
4547
|
+
if (choice === "cancel") {
|
|
4548
|
+
logger.info(t("backup_cancel"));
|
|
4549
|
+
return {
|
|
4550
|
+
success: false,
|
|
4551
|
+
pluginId: opts.pluginId,
|
|
4552
|
+
skillsCount: 0,
|
|
4553
|
+
agentsCount: 0,
|
|
4554
|
+
errors: [t("backup_cancel")],
|
|
4555
|
+
warnings: []
|
|
4556
|
+
};
|
|
4405
4557
|
}
|
|
4558
|
+
if (choice === "keep") {
|
|
4559
|
+
preservedTargets.push(target);
|
|
4560
|
+
logger.info(t("unowned_preserved").replace("{file}", target));
|
|
4561
|
+
continue;
|
|
4562
|
+
}
|
|
4563
|
+
const backup = createBackup(target, UNOWNED_PLUGIN_ID, t("unowned_backup_label"));
|
|
4564
|
+
if (!backup) {
|
|
4565
|
+
logger.error(t("backup_failed"));
|
|
4566
|
+
return {
|
|
4567
|
+
success: false,
|
|
4568
|
+
pluginId: opts.pluginId,
|
|
4569
|
+
skillsCount: 0,
|
|
4570
|
+
agentsCount: 0,
|
|
4571
|
+
errors: [t("backup_failed")],
|
|
4572
|
+
warnings: []
|
|
4573
|
+
};
|
|
4574
|
+
}
|
|
4575
|
+
backups.push(backup);
|
|
4576
|
+
logger.success(`${t("backup_created")}: ${backup.filePath}`);
|
|
4406
4577
|
}
|
|
4407
4578
|
if (plugin.installSkills && plugin.installSkills.length > 0) {
|
|
4408
4579
|
const result = await installViaManifest(
|
|
@@ -4410,7 +4581,8 @@ async function installPlugin(opts) {
|
|
|
4410
4581
|
opts.repoPath,
|
|
4411
4582
|
opts.tool,
|
|
4412
4583
|
opts.level,
|
|
4413
|
-
opts.installPath
|
|
4584
|
+
opts.installPath,
|
|
4585
|
+
preservedTargets
|
|
4414
4586
|
);
|
|
4415
4587
|
if (result.success) {
|
|
4416
4588
|
try {
|
|
@@ -4422,16 +4594,21 @@ async function installPlugin(opts) {
|
|
|
4422
4594
|
cwd,
|
|
4423
4595
|
configRoot,
|
|
4424
4596
|
result.manifest,
|
|
4425
|
-
plugin.externalRepos?.map((r) =>
|
|
4426
|
-
plugin.configRootConfigLink
|
|
4597
|
+
plugin.externalRepos?.map((r) => basename3(r.dir)),
|
|
4598
|
+
plugin.configRootConfigLink,
|
|
4599
|
+
preservedTargets
|
|
4427
4600
|
);
|
|
4428
|
-
if (
|
|
4429
|
-
record.
|
|
4430
|
-
filePath:
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4601
|
+
if (backups.length > 0) {
|
|
4602
|
+
record.backups = backups.map((b) => ({
|
|
4603
|
+
filePath: b.filePath,
|
|
4604
|
+
originalPath: b.originalPath,
|
|
4605
|
+
fromPluginId: b.pluginId,
|
|
4606
|
+
fromPluginName: b.pluginName,
|
|
4607
|
+
backupTime: b.backupTime
|
|
4608
|
+
}));
|
|
4609
|
+
}
|
|
4610
|
+
if (preservedTargets.length > 0) {
|
|
4611
|
+
record.preservedTargets = [...preservedTargets];
|
|
4435
4612
|
}
|
|
4436
4613
|
writeRecord(record);
|
|
4437
4614
|
} catch {
|
|
@@ -4519,16 +4696,21 @@ async function installPlugin(opts) {
|
|
|
4519
4696
|
cwd,
|
|
4520
4697
|
configRoot,
|
|
4521
4698
|
manifest,
|
|
4522
|
-
plugin.externalRepos?.map((r) =>
|
|
4523
|
-
plugin.configRootConfigLink
|
|
4699
|
+
plugin.externalRepos?.map((r) => basename3(r.dir)),
|
|
4700
|
+
plugin.configRootConfigLink,
|
|
4701
|
+
preservedTargets
|
|
4524
4702
|
);
|
|
4525
|
-
if (
|
|
4526
|
-
record.
|
|
4527
|
-
filePath:
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4703
|
+
if (backups.length > 0) {
|
|
4704
|
+
record.backups = backups.map((b) => ({
|
|
4705
|
+
filePath: b.filePath,
|
|
4706
|
+
originalPath: b.originalPath,
|
|
4707
|
+
fromPluginId: b.pluginId,
|
|
4708
|
+
fromPluginName: b.pluginName,
|
|
4709
|
+
backupTime: b.backupTime
|
|
4710
|
+
}));
|
|
4711
|
+
}
|
|
4712
|
+
if (preservedTargets.length > 0) {
|
|
4713
|
+
record.preservedTargets = [...preservedTargets];
|
|
4532
4714
|
}
|
|
4533
4715
|
writeRecord(record);
|
|
4534
4716
|
} catch {
|
|
@@ -4650,7 +4832,7 @@ function installerSupportsBundledFlag() {
|
|
|
4650
4832
|
}
|
|
4651
4833
|
async function delegateInstall(options) {
|
|
4652
4834
|
const { pluginId, tool, level } = options;
|
|
4653
|
-
const target =
|
|
4835
|
+
const target = resolve4(options.target || process.cwd());
|
|
4654
4836
|
const displayName = options.displayName || pluginId;
|
|
4655
4837
|
const result = {
|
|
4656
4838
|
success: false,
|
|
@@ -4776,8 +4958,8 @@ init_fs_helpers();
|
|
|
4776
4958
|
init_constants();
|
|
4777
4959
|
init_logger();
|
|
4778
4960
|
init_i18n();
|
|
4779
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync7, symlinkSync as symlinkSync2, readdirSync as readdirSync9, rmSync as rmSync5, realpathSync as
|
|
4780
|
-
import { join as join17, dirname as
|
|
4961
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, symlinkSync as symlinkSync2, readdirSync as readdirSync9, rmSync as rmSync5, realpathSync as realpathSync3, readlinkSync as readlinkSync2, cpSync as cpSync2 } from "fs";
|
|
4962
|
+
import { join as join17, dirname as dirname8, basename as basename4, isAbsolute as isAbsolute2 } from "path";
|
|
4781
4963
|
import { select as select3, checkbox, Separator as Separator2 } from "@inquirer/prompts";
|
|
4782
4964
|
import chalk5 from "chalk";
|
|
4783
4965
|
import Table from "cli-table3";
|
|
@@ -4805,7 +4987,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
4805
4987
|
continue;
|
|
4806
4988
|
}
|
|
4807
4989
|
try {
|
|
4808
|
-
const resolvedSource =
|
|
4990
|
+
const resolvedSource = realpathSync3(sourcePath);
|
|
4809
4991
|
if (isSymlink(targetPath)) {
|
|
4810
4992
|
try {
|
|
4811
4993
|
const currentTarget = readlinkSync2(targetPath);
|
|
@@ -4884,11 +5066,11 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
4884
5066
|
rmSync5(skillsDir, { recursive: true });
|
|
4885
5067
|
logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
|
|
4886
5068
|
if (tool === "codex") {
|
|
4887
|
-
const agentsRoot =
|
|
5069
|
+
const agentsRoot = dirname8(skillsDir);
|
|
4888
5070
|
try {
|
|
4889
5071
|
if (existsSync18(agentsRoot) && readdirSync9(agentsRoot).length === 0) {
|
|
4890
5072
|
rmSync5(agentsRoot, { recursive: true });
|
|
4891
|
-
logger.step(` ${t("uninstall_clean_empty_dir")}: ${
|
|
5073
|
+
logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename4(agentsRoot)}/`);
|
|
4892
5074
|
}
|
|
4893
5075
|
} catch {
|
|
4894
5076
|
}
|
|
@@ -5298,7 +5480,7 @@ function resolveSkillSourcePath(skill, repoPath) {
|
|
|
5298
5480
|
if (skill.filePath) {
|
|
5299
5481
|
const absPath = isAbsolute2(skill.filePath) ? skill.filePath : join17(repoPath, skill.filePath);
|
|
5300
5482
|
if (existsSync18(absPath)) {
|
|
5301
|
-
return
|
|
5483
|
+
return dirname8(absPath);
|
|
5302
5484
|
}
|
|
5303
5485
|
}
|
|
5304
5486
|
return join17(repoPath, skill.source, skill.id);
|
|
@@ -6354,7 +6536,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
|
|
|
6354
6536
|
// src/commands/uninstall.ts
|
|
6355
6537
|
init_registry();
|
|
6356
6538
|
import { existsSync as existsSync21, unlinkSync as unlinkSync8, rmdirSync as rmdirSync2, readdirSync as readdirSync11, readFileSync as readFileSync15 } from "fs";
|
|
6357
|
-
import { resolve as
|
|
6539
|
+
import { resolve as resolve5, basename as basename5, sep as sep3, join as join20 } from "path";
|
|
6358
6540
|
import chalk11 from "chalk";
|
|
6359
6541
|
import { select as select5, checkbox as checkbox2, Separator as Separator4, confirm as confirm3 } from "@inquirer/prompts";
|
|
6360
6542
|
init_config();
|
|
@@ -6740,7 +6922,7 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6740
6922
|
installPath,
|
|
6741
6923
|
configRoot2,
|
|
6742
6924
|
manifest,
|
|
6743
|
-
plugin.externalRepos?.map((r) =>
|
|
6925
|
+
plugin.externalRepos?.map((r) => basename5(r.dir)),
|
|
6744
6926
|
plugin.configRootConfigLink
|
|
6745
6927
|
);
|
|
6746
6928
|
break;
|
|
@@ -6755,14 +6937,15 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6755
6937
|
}
|
|
6756
6938
|
logger.info(`${t("uninstall_in_progress")} ${plugin.displayName}...`);
|
|
6757
6939
|
const configRoot = record.configRoot;
|
|
6758
|
-
const allowedBases = [
|
|
6940
|
+
const allowedBases = [resolve5(configRoot), resolve5(record.installPath)];
|
|
6759
6941
|
if (record.tool === "codex") {
|
|
6760
|
-
allowedBases.push(
|
|
6942
|
+
allowedBases.push(resolve5(getSkillsRoot(record.tool, record.level, record.installPath)));
|
|
6761
6943
|
}
|
|
6762
6944
|
const isSafePath = (p) => {
|
|
6763
|
-
const resolved =
|
|
6945
|
+
const resolved = resolve5(p);
|
|
6764
6946
|
return allowedBases.some((base) => resolved === base || resolved.startsWith(base + sep3));
|
|
6765
6947
|
};
|
|
6948
|
+
const preservedPaths = new Set((record.preservedTargets || []).map((p) => resolve5(p)));
|
|
6766
6949
|
let removedFiles = 0;
|
|
6767
6950
|
let removedDirs = 0;
|
|
6768
6951
|
const configFileName = record.tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
@@ -6772,13 +6955,15 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6772
6955
|
if (record.level === "project" && configRootConfigPath !== installPathConfigPath && !record.files.includes(configRootConfigPath) && (existsSync21(configRootConfigPath) || isSymlink(configRootConfigPath))) {
|
|
6773
6956
|
extraFiles.push(configRootConfigPath);
|
|
6774
6957
|
}
|
|
6775
|
-
const allFiles = [...record.files, ...extraFiles]
|
|
6958
|
+
const allFiles = [...record.files, ...extraFiles].filter(
|
|
6959
|
+
(filePath) => !preservedPaths.has(resolve5(filePath))
|
|
6960
|
+
);
|
|
6776
6961
|
for (const filePath of allFiles) {
|
|
6777
6962
|
if (!isSafePath(filePath)) continue;
|
|
6778
6963
|
try {
|
|
6779
6964
|
if (existsSync21(filePath) || isSymlink(filePath)) {
|
|
6780
6965
|
unlinkSync8(filePath);
|
|
6781
|
-
const name =
|
|
6966
|
+
const name = basename5(filePath);
|
|
6782
6967
|
logger.step(` ${t("uninstall_remove_label")}: ${name}`);
|
|
6783
6968
|
removedFiles++;
|
|
6784
6969
|
}
|
|
@@ -6788,14 +6973,14 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6788
6973
|
const sortedDirs = [...record.directories].filter(isSafePath).sort((a, b) => b.length - a.length);
|
|
6789
6974
|
for (const dirPath of sortedDirs) {
|
|
6790
6975
|
try {
|
|
6791
|
-
if (
|
|
6976
|
+
if (resolve5(dirPath) === resolve5(configRoot)) {
|
|
6792
6977
|
continue;
|
|
6793
6978
|
}
|
|
6794
6979
|
if (existsSync21(dirPath)) {
|
|
6795
6980
|
const entries = readdirSync11(dirPath);
|
|
6796
6981
|
if (entries.length === 0) {
|
|
6797
6982
|
rmdirSync2(dirPath);
|
|
6798
|
-
const name =
|
|
6983
|
+
const name = basename5(dirPath);
|
|
6799
6984
|
logger.step(` ${t("uninstall_clean_empty_dir")}: ${name}/`);
|
|
6800
6985
|
removedDirs++;
|
|
6801
6986
|
}
|
|
@@ -6805,10 +6990,10 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6805
6990
|
}
|
|
6806
6991
|
if (record.tool === "codex") {
|
|
6807
6992
|
try {
|
|
6808
|
-
const agentsRoot =
|
|
6993
|
+
const agentsRoot = resolve5(getSkillsRoot(record.tool, record.level, record.installPath), "..");
|
|
6809
6994
|
if (existsSync21(agentsRoot) && readdirSync11(agentsRoot).length === 0) {
|
|
6810
6995
|
rmdirSync2(agentsRoot);
|
|
6811
|
-
logger.step(` ${t("uninstall_clean_empty_dir")}: ${
|
|
6996
|
+
logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename5(agentsRoot)}/`);
|
|
6812
6997
|
removedDirs++;
|
|
6813
6998
|
}
|
|
6814
6999
|
} catch {
|
|
@@ -6820,16 +7005,27 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6820
7005
|
installPath: record.installPath
|
|
6821
7006
|
});
|
|
6822
7007
|
removeInstalledPlugin(plugin.id);
|
|
6823
|
-
const
|
|
7008
|
+
const backupDirs = resolve5(record.installPath) === resolve5(configRoot) ? [configRoot] : [configRoot, record.installPath];
|
|
7009
|
+
const recordBackups = [
|
|
7010
|
+
...record.backups || [],
|
|
7011
|
+
...record.backup ? [{ ...record.backup, originalPath: join20(configRoot, configFileName) }] : []
|
|
7012
|
+
];
|
|
7013
|
+
const backups = findBackups(backupDirs).map((b) => {
|
|
7014
|
+
const recorded = recordBackups.find((rb) => resolve5(rb.filePath) === resolve5(b.filePath));
|
|
7015
|
+
return recorded ? { ...b, originalPath: recorded.originalPath } : b;
|
|
7016
|
+
});
|
|
6824
7017
|
const otherBackups = backups.filter((b) => b.pluginId !== pluginId);
|
|
6825
7018
|
if (!batchMode && otherBackups.length > 0) {
|
|
6826
7019
|
const choice = await showRestorePrompt(otherBackups);
|
|
6827
7020
|
if (choice !== "none") {
|
|
6828
|
-
const
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
7021
|
+
const backupInfo = otherBackups.find((b) => b.filePath === choice);
|
|
7022
|
+
const restoreTarget = backupInfo?.originalPath || join20(configRoot, configFileName);
|
|
7023
|
+
if (isSafePath(restoreTarget)) {
|
|
7024
|
+
const restored = restoreBackup(choice, restoreTarget);
|
|
7025
|
+
if (restored) {
|
|
7026
|
+
logger.success(`${t("backup_restore_success")}: ${backupInfo?.pluginName || ""} -> ${restoreTarget}`);
|
|
7027
|
+
deleteBackup(choice);
|
|
7028
|
+
}
|
|
6833
7029
|
}
|
|
6834
7030
|
}
|
|
6835
7031
|
} else if (batchMode && otherBackups.length > 0) {
|
|
@@ -7101,7 +7297,7 @@ init_config();
|
|
|
7101
7297
|
init_i18n();
|
|
7102
7298
|
import { readFileSync as readFileSync16, existsSync as existsSync23 } from "fs";
|
|
7103
7299
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7104
|
-
import { dirname as
|
|
7300
|
+
import { dirname as dirname9, join as join22 } from "path";
|
|
7105
7301
|
function readVersion() {
|
|
7106
7302
|
try {
|
|
7107
7303
|
if (typeof INSTALL_HELPER_VERSION !== "undefined" && INSTALL_HELPER_VERSION) {
|
|
@@ -7111,7 +7307,7 @@ function readVersion() {
|
|
|
7111
7307
|
}
|
|
7112
7308
|
try {
|
|
7113
7309
|
const __filename5 = fileURLToPath5(import.meta.url);
|
|
7114
|
-
const __dirname5 =
|
|
7310
|
+
const __dirname5 = dirname9(__filename5);
|
|
7115
7311
|
const candidates = [
|
|
7116
7312
|
join22(__dirname5, "..", "package.json"),
|
|
7117
7313
|
join22(__dirname5, "package.json"),
|