@cannbot-ai/install-helper 1.2.1 → 1.2.2-beta.1
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 +345 -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,60 @@ 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 isPreservedTarget(targetPath) {
|
|
3925
|
+
const resolved = resolve3(targetPath);
|
|
3926
|
+
return readAllRecords().some(
|
|
3927
|
+
(record) => (record.preservedTargets || []).some((p) => resolve3(p) === resolved)
|
|
3928
|
+
);
|
|
3929
|
+
}
|
|
3930
|
+
function findBackups(configRoot) {
|
|
3931
|
+
const dirs = Array.isArray(configRoot) ? configRoot : [configRoot];
|
|
3888
3932
|
const backups = [];
|
|
3889
|
-
for (const
|
|
3890
|
-
if (
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
const
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
pluginId,
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3933
|
+
for (const dir of dirs) {
|
|
3934
|
+
if (!existsSync14(dir)) {
|
|
3935
|
+
continue;
|
|
3936
|
+
}
|
|
3937
|
+
const files = readdirSync7(dir);
|
|
3938
|
+
for (const file of files) {
|
|
3939
|
+
if (file.includes(".cannbot-backup.")) {
|
|
3940
|
+
const parts = file.split(".cannbot-backup.");
|
|
3941
|
+
if (parts.length === 2) {
|
|
3942
|
+
const pluginIdAndTime = parts[1];
|
|
3943
|
+
const lastDotIndex = pluginIdAndTime.lastIndexOf(".");
|
|
3944
|
+
if (lastDotIndex > 0) {
|
|
3945
|
+
const pluginId = pluginIdAndTime.substring(0, lastDotIndex);
|
|
3946
|
+
const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
|
|
3947
|
+
const plugin = findPlugin(pluginId);
|
|
3948
|
+
backups.push({
|
|
3949
|
+
filePath: join13(dir, file),
|
|
3950
|
+
originalPath: join13(dir, parts[0]),
|
|
3951
|
+
pluginId,
|
|
3952
|
+
pluginName: plugin?.displayName || pluginId,
|
|
3953
|
+
backupTime: timestamp
|
|
3954
|
+
});
|
|
3955
|
+
}
|
|
3905
3956
|
}
|
|
3906
3957
|
}
|
|
3907
3958
|
}
|
|
3908
3959
|
}
|
|
3909
3960
|
return backups.sort((a, b) => b.backupTime.localeCompare(a.backupTime));
|
|
3910
3961
|
}
|
|
3911
|
-
function restoreBackup(backupPath,
|
|
3962
|
+
function restoreBackup(backupPath, targetPath) {
|
|
3912
3963
|
try {
|
|
3913
|
-
|
|
3914
|
-
copyFileSync(backupPath, agentsFile);
|
|
3964
|
+
copyFileSync(backupPath, targetPath);
|
|
3915
3965
|
return true;
|
|
3916
3966
|
} catch {
|
|
3917
3967
|
return false;
|
|
@@ -3939,13 +3989,21 @@ function formatTimestamp(date) {
|
|
|
3939
3989
|
}
|
|
3940
3990
|
function readAllRecords() {
|
|
3941
3991
|
const records = [];
|
|
3942
|
-
const
|
|
3943
|
-
|
|
3944
|
-
records
|
|
3992
|
+
const installsDir = join13(getCannbotConfigDir(), "installs");
|
|
3993
|
+
if (!existsSync14(installsDir)) {
|
|
3994
|
+
return records;
|
|
3995
|
+
}
|
|
3996
|
+
for (const file of readdirSync7(installsDir)) {
|
|
3997
|
+
if (!file.endsWith(".json") || file === "skills.json") continue;
|
|
3998
|
+
const pluginId = file.replace(/\.json$/, "");
|
|
3999
|
+
records.push(...readRecords(pluginId));
|
|
3945
4000
|
}
|
|
3946
4001
|
return records;
|
|
3947
4002
|
}
|
|
3948
4003
|
|
|
4004
|
+
// src/core/installer.ts
|
|
4005
|
+
init_fs_helpers();
|
|
4006
|
+
|
|
3949
4007
|
// src/ui/backup-prompts.ts
|
|
3950
4008
|
init_i18n();
|
|
3951
4009
|
import { select as select2 } from "@inquirer/prompts";
|
|
@@ -3969,12 +4027,31 @@ async function showOverwriteWarning(currentPluginName, newPluginName) {
|
|
|
3969
4027
|
});
|
|
3970
4028
|
return choice;
|
|
3971
4029
|
}
|
|
4030
|
+
async function showUnownedFileWarning(filePath, newPluginName) {
|
|
4031
|
+
console.log();
|
|
4032
|
+
console.log(chalk4.yellow(` \u26A0\uFE0F ${t("unowned_file_detected")}`));
|
|
4033
|
+
console.log();
|
|
4034
|
+
console.log(` ${t("unowned_file_path")}: ${chalk4.cyan(filePath)}`);
|
|
4035
|
+
console.log(` ${t("backup_installing")}: ${chalk4.cyan(newPluginName)}`);
|
|
4036
|
+
console.log();
|
|
4037
|
+
console.log(` ${t("unowned_file_warning")}`);
|
|
4038
|
+
console.log();
|
|
4039
|
+
const choice = await select2({
|
|
4040
|
+
message: t("backup_select_action"),
|
|
4041
|
+
choices: [
|
|
4042
|
+
{ name: t("unowned_file_keep"), value: "keep" },
|
|
4043
|
+
{ name: t("unowned_file_replace"), value: "replace" },
|
|
4044
|
+
{ name: t("backup_cancel"), value: "cancel" }
|
|
4045
|
+
]
|
|
4046
|
+
});
|
|
4047
|
+
return choice;
|
|
4048
|
+
}
|
|
3972
4049
|
async function showRestorePrompt(backups) {
|
|
3973
4050
|
console.log();
|
|
3974
4051
|
console.log(chalk4.cyan(` ${t("backup_restore_prompt")}`));
|
|
3975
4052
|
console.log();
|
|
3976
4053
|
const choices = backups.map((b) => ({
|
|
3977
|
-
name: `${t("backup_restore")} ${b.pluginName} (${b.backupTime})`,
|
|
4054
|
+
name: b.pluginId === "unowned" ? `${t("backup_restore_user_file")} ${b.originalPath} (${b.backupTime})` : `${t("backup_restore")} ${b.pluginName} (${b.backupTime})`,
|
|
3978
4055
|
value: b.filePath
|
|
3979
4056
|
}));
|
|
3980
4057
|
choices.push({ name: t("backup_only_uninstall"), value: "none" });
|
|
@@ -3991,7 +4068,7 @@ init_fs_helpers();
|
|
|
3991
4068
|
init_logger();
|
|
3992
4069
|
init_i18n();
|
|
3993
4070
|
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";
|
|
4071
|
+
import { join as join14, basename as basename2 } from "path";
|
|
3995
4072
|
import { execa as execa4 } from "execa";
|
|
3996
4073
|
var ISSUE_HANDLER_ID = "gitcode-issue-handler";
|
|
3997
4074
|
var ISSUE_HANDLER_CONFIG_FILES = ["classify_config.yaml", "operator_owners.yaml"];
|
|
@@ -4058,7 +4135,25 @@ function installLink(source, target) {
|
|
|
4058
4135
|
return "failed";
|
|
4059
4136
|
}
|
|
4060
4137
|
}
|
|
4061
|
-
function
|
|
4138
|
+
function configFileTargets(pluginDir, configFile, tool, level, configRoot, installPath, configRootConfigLink) {
|
|
4139
|
+
const sourcePath = join14(pluginDir, configFile);
|
|
4140
|
+
if (!existsSync15(sourcePath)) return [];
|
|
4141
|
+
const agentsFileName = getAgentsFileName(tool);
|
|
4142
|
+
const targets = [];
|
|
4143
|
+
if (level === "project") {
|
|
4144
|
+
targets.push(join14(installPath, agentsFileName));
|
|
4145
|
+
if (configRootConfigLink !== false) {
|
|
4146
|
+
const configRootTarget = join14(configRoot, agentsFileName);
|
|
4147
|
+
if (!targets.includes(configRootTarget)) {
|
|
4148
|
+
targets.push(configRootTarget);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
} else {
|
|
4152
|
+
targets.push(join14(configRoot, agentsFileName));
|
|
4153
|
+
}
|
|
4154
|
+
return targets;
|
|
4155
|
+
}
|
|
4156
|
+
function installConfigFile(pluginDir, configFile, tool, level, configRoot, installPath, configRootConfigLink, preservedTargets) {
|
|
4062
4157
|
const sourcePath = join14(pluginDir, configFile);
|
|
4063
4158
|
if (!existsSync15(sourcePath)) return;
|
|
4064
4159
|
const agentsFileName = getAgentsFileName(tool);
|
|
@@ -4069,26 +4164,34 @@ function installConfigFile(pluginDir, configFile, tool, level, configRoot, insta
|
|
|
4069
4164
|
} else {
|
|
4070
4165
|
primaryTarget = join14(configRoot, agentsFileName);
|
|
4071
4166
|
}
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
removePath(primaryTarget);
|
|
4076
|
-
}
|
|
4167
|
+
if (preservedTargets?.includes(primaryTarget)) {
|
|
4168
|
+
logger.info(t("install_config_preserved").replace("{file}", primaryTarget));
|
|
4169
|
+
} else {
|
|
4077
4170
|
try {
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4171
|
+
const resolvedSource = realpathSync(sourcePath);
|
|
4172
|
+
if (existsSync15(primaryTarget) || isSymlink(primaryTarget)) {
|
|
4173
|
+
removePath(primaryTarget);
|
|
4174
|
+
}
|
|
4175
|
+
try {
|
|
4176
|
+
symlinkSync(resolvedSource, primaryTarget);
|
|
4177
|
+
} catch (e) {
|
|
4178
|
+
if (e.code === "EPERM") {
|
|
4179
|
+
copyFileSync2(sourcePath, primaryTarget);
|
|
4180
|
+
} else {
|
|
4181
|
+
throw e;
|
|
4182
|
+
}
|
|
4084
4183
|
}
|
|
4184
|
+
} catch (e) {
|
|
4185
|
+
logger.warn(t("install_config_failed").replace("{error}", e.message));
|
|
4085
4186
|
}
|
|
4086
|
-
} catch (e) {
|
|
4087
|
-
logger.warn(t("install_config_failed").replace("{error}", e.message));
|
|
4088
4187
|
}
|
|
4089
4188
|
if (isProjectLevel && primaryTarget !== join14(configRoot, agentsFileName)) {
|
|
4090
4189
|
if (configRootConfigLink === false) return;
|
|
4091
4190
|
const configRootTarget = join14(configRoot, agentsFileName);
|
|
4191
|
+
if (preservedTargets?.includes(configRootTarget)) {
|
|
4192
|
+
logger.info(t("install_config_preserved").replace("{file}", configRootTarget));
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
4092
4195
|
if (existsSync15(configRootTarget) || isSymlink(configRootTarget)) {
|
|
4093
4196
|
removePath(configRootTarget);
|
|
4094
4197
|
}
|
|
@@ -4132,7 +4235,7 @@ async function installExternalRepos(repos, repoPath, configRoot, installPath, le
|
|
|
4132
4235
|
continue;
|
|
4133
4236
|
}
|
|
4134
4237
|
}
|
|
4135
|
-
const linkName =
|
|
4238
|
+
const linkName = basename2(repo.dir);
|
|
4136
4239
|
const resolved = realpathSync(targetDir);
|
|
4137
4240
|
const shouldConfigRootLink = repo.configRootLink !== false && (level === "global" || repo.configRootLink === true);
|
|
4138
4241
|
if (shouldConfigRootLink) {
|
|
@@ -4207,7 +4310,7 @@ function writeCannbotManifest(configRoot, pluginId, version, level, tool, skills
|
|
|
4207
4310
|
writeFileSync4(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
4208
4311
|
return manifest;
|
|
4209
4312
|
}
|
|
4210
|
-
async function installViaManifest(plugin, repoPath, tool, level, installPath) {
|
|
4313
|
+
async function installViaManifest(plugin, repoPath, tool, level, installPath, preservedTargets) {
|
|
4211
4314
|
const cwd = installPath || process.cwd();
|
|
4212
4315
|
const configRoot = getConfigRoot(tool, level, installPath);
|
|
4213
4316
|
const pluginDir = join14(repoPath, plugin.dir);
|
|
@@ -4278,7 +4381,7 @@ async function installViaManifest(plugin, repoPath, tool, level, installPath) {
|
|
|
4278
4381
|
logger.warn(t("install_agent_failed").replace("{name}", agentFile));
|
|
4279
4382
|
}
|
|
4280
4383
|
}
|
|
4281
|
-
installConfigFile(pluginDir, plugin.configFile || "AGENTS.md", tool, level, configRoot, cwd, plugin.configRootConfigLink);
|
|
4384
|
+
installConfigFile(pluginDir, plugin.configFile || "AGENTS.md", tool, level, configRoot, cwd, plugin.configRootConfigLink, preservedTargets);
|
|
4282
4385
|
installWorkflows(pluginDir, configRoot);
|
|
4283
4386
|
await installExternalRepos(plugin.externalRepos, repoPath, configRoot, cwd, level);
|
|
4284
4387
|
const cannbotManifest = writeCannbotManifest(
|
|
@@ -4334,6 +4437,28 @@ function scriptSupportsTool(scriptPath, tool) {
|
|
|
4334
4437
|
return true;
|
|
4335
4438
|
}
|
|
4336
4439
|
}
|
|
4440
|
+
function classifyConfigTarget(targetPath, pluginConfigSource, pluginId, pluginName, configRoot, tool, installPath) {
|
|
4441
|
+
if (isSymlink(targetPath)) {
|
|
4442
|
+
try {
|
|
4443
|
+
if (realpathSync2(targetPath) === realpathSync2(pluginConfigSource)) {
|
|
4444
|
+
return { kind: "same-plugin", pluginId, pluginName };
|
|
4445
|
+
}
|
|
4446
|
+
} catch {
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
if (isPreservedTarget(targetPath)) {
|
|
4450
|
+
return { kind: "unowned", pluginId: UNOWNED_PLUGIN_ID, pluginName: UNOWNED_PLUGIN_ID };
|
|
4451
|
+
}
|
|
4452
|
+
const recordOwner = findRecordOwner(targetPath);
|
|
4453
|
+
if (recordOwner) {
|
|
4454
|
+
return recordOwner.pluginId === pluginId ? { kind: "same-plugin", pluginId, pluginName } : { kind: "other-plugin", ...recordOwner };
|
|
4455
|
+
}
|
|
4456
|
+
const currentPlugin = detectCurrentPlugin(configRoot, tool, installPath);
|
|
4457
|
+
if (currentPlugin) {
|
|
4458
|
+
return currentPlugin.pluginId === pluginId ? { kind: "same-plugin", pluginId, pluginName } : { kind: "other-plugin", ...currentPlugin };
|
|
4459
|
+
}
|
|
4460
|
+
return { kind: "unowned", pluginId: UNOWNED_PLUGIN_ID, pluginName: UNOWNED_PLUGIN_ID };
|
|
4461
|
+
}
|
|
4337
4462
|
async function installPlugin(opts) {
|
|
4338
4463
|
const plugin = opts.plugin ?? getPluginById(opts.pluginId);
|
|
4339
4464
|
if (!plugin) {
|
|
@@ -4359,38 +4484,55 @@ async function installPlugin(opts) {
|
|
|
4359
4484
|
const pluginDir = isAbsolute(plugin.dir) ? plugin.dir : join15(opts.repoPath, plugin.dir);
|
|
4360
4485
|
const cwd = opts.installPath || process.cwd();
|
|
4361
4486
|
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
|
-
|
|
4487
|
+
const pluginConfigSource = join15(pluginDir, plugin.configFile || "AGENTS.md");
|
|
4488
|
+
const existingTargets = configFileTargets(
|
|
4489
|
+
pluginDir,
|
|
4490
|
+
plugin.configFile || "AGENTS.md",
|
|
4491
|
+
opts.tool,
|
|
4492
|
+
opts.level,
|
|
4493
|
+
configRoot,
|
|
4494
|
+
cwd,
|
|
4495
|
+
plugin.configRootConfigLink
|
|
4496
|
+
).filter((p) => existsSync16(p) || isSymlink(p));
|
|
4497
|
+
const backups = [];
|
|
4498
|
+
const preservedTargets = [];
|
|
4499
|
+
const promptedPlugins = /* @__PURE__ */ new Set();
|
|
4500
|
+
for (const target of existingTargets) {
|
|
4501
|
+
const owner = classifyConfigTarget(
|
|
4502
|
+
target,
|
|
4503
|
+
pluginConfigSource,
|
|
4504
|
+
opts.pluginId,
|
|
4505
|
+
plugin.displayName,
|
|
4506
|
+
configRoot,
|
|
4507
|
+
opts.tool,
|
|
4508
|
+
cwd
|
|
4509
|
+
);
|
|
4510
|
+
if (owner.kind === "same-plugin") {
|
|
4511
|
+
const backup2 = createBackup(target, owner.pluginId, owner.pluginName);
|
|
4512
|
+
if (backup2) backups.push(backup2);
|
|
4513
|
+
continue;
|
|
4385
4514
|
}
|
|
4386
|
-
if (
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4515
|
+
if (owner.kind === "other-plugin") {
|
|
4516
|
+
if (!promptedPlugins.has(owner.pluginId)) {
|
|
4517
|
+
promptedPlugins.add(owner.pluginId);
|
|
4518
|
+
let choice2 = "overwrite";
|
|
4519
|
+
if (!opts.yes) {
|
|
4520
|
+
choice2 = await showOverwriteWarning(owner.pluginName, plugin.displayName);
|
|
4521
|
+
}
|
|
4522
|
+
if (choice2 === "cancel") {
|
|
4523
|
+
logger.info(t("backup_cancel"));
|
|
4524
|
+
return {
|
|
4525
|
+
success: false,
|
|
4526
|
+
pluginId: opts.pluginId,
|
|
4527
|
+
skillsCount: 0,
|
|
4528
|
+
agentsCount: 0,
|
|
4529
|
+
errors: [t("backup_cancel")],
|
|
4530
|
+
warnings: []
|
|
4531
|
+
};
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
const backup2 = createBackup(target, owner.pluginId, owner.pluginName);
|
|
4535
|
+
if (!backup2) {
|
|
4394
4536
|
logger.error(t("backup_failed"));
|
|
4395
4537
|
return {
|
|
4396
4538
|
success: false,
|
|
@@ -4401,8 +4543,46 @@ async function installPlugin(opts) {
|
|
|
4401
4543
|
warnings: []
|
|
4402
4544
|
};
|
|
4403
4545
|
}
|
|
4404
|
-
|
|
4546
|
+
backups.push(backup2);
|
|
4547
|
+
logger.success(`${t("backup_created")}: ${backup2.filePath}`);
|
|
4548
|
+
continue;
|
|
4549
|
+
}
|
|
4550
|
+
if (opts.yes) {
|
|
4551
|
+
preservedTargets.push(target);
|
|
4552
|
+
logger.warn(t("unowned_preserved_yes").replace("{file}", target));
|
|
4553
|
+
continue;
|
|
4554
|
+
}
|
|
4555
|
+
const choice = await showUnownedFileWarning(target, plugin.displayName);
|
|
4556
|
+
if (choice === "cancel") {
|
|
4557
|
+
logger.info(t("backup_cancel"));
|
|
4558
|
+
return {
|
|
4559
|
+
success: false,
|
|
4560
|
+
pluginId: opts.pluginId,
|
|
4561
|
+
skillsCount: 0,
|
|
4562
|
+
agentsCount: 0,
|
|
4563
|
+
errors: [t("backup_cancel")],
|
|
4564
|
+
warnings: []
|
|
4565
|
+
};
|
|
4566
|
+
}
|
|
4567
|
+
if (choice === "keep") {
|
|
4568
|
+
preservedTargets.push(target);
|
|
4569
|
+
logger.info(t("unowned_preserved").replace("{file}", target));
|
|
4570
|
+
continue;
|
|
4571
|
+
}
|
|
4572
|
+
const backup = createBackup(target, UNOWNED_PLUGIN_ID, t("unowned_backup_label"));
|
|
4573
|
+
if (!backup) {
|
|
4574
|
+
logger.error(t("backup_failed"));
|
|
4575
|
+
return {
|
|
4576
|
+
success: false,
|
|
4577
|
+
pluginId: opts.pluginId,
|
|
4578
|
+
skillsCount: 0,
|
|
4579
|
+
agentsCount: 0,
|
|
4580
|
+
errors: [t("backup_failed")],
|
|
4581
|
+
warnings: []
|
|
4582
|
+
};
|
|
4405
4583
|
}
|
|
4584
|
+
backups.push(backup);
|
|
4585
|
+
logger.success(`${t("backup_created")}: ${backup.filePath}`);
|
|
4406
4586
|
}
|
|
4407
4587
|
if (plugin.installSkills && plugin.installSkills.length > 0) {
|
|
4408
4588
|
const result = await installViaManifest(
|
|
@@ -4410,7 +4590,8 @@ async function installPlugin(opts) {
|
|
|
4410
4590
|
opts.repoPath,
|
|
4411
4591
|
opts.tool,
|
|
4412
4592
|
opts.level,
|
|
4413
|
-
opts.installPath
|
|
4593
|
+
opts.installPath,
|
|
4594
|
+
preservedTargets
|
|
4414
4595
|
);
|
|
4415
4596
|
if (result.success) {
|
|
4416
4597
|
try {
|
|
@@ -4422,16 +4603,21 @@ async function installPlugin(opts) {
|
|
|
4422
4603
|
cwd,
|
|
4423
4604
|
configRoot,
|
|
4424
4605
|
result.manifest,
|
|
4425
|
-
plugin.externalRepos?.map((r) =>
|
|
4426
|
-
plugin.configRootConfigLink
|
|
4606
|
+
plugin.externalRepos?.map((r) => basename3(r.dir)),
|
|
4607
|
+
plugin.configRootConfigLink,
|
|
4608
|
+
preservedTargets
|
|
4427
4609
|
);
|
|
4428
|
-
if (
|
|
4429
|
-
record.
|
|
4430
|
-
filePath:
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4610
|
+
if (backups.length > 0) {
|
|
4611
|
+
record.backups = backups.map((b) => ({
|
|
4612
|
+
filePath: b.filePath,
|
|
4613
|
+
originalPath: b.originalPath,
|
|
4614
|
+
fromPluginId: b.pluginId,
|
|
4615
|
+
fromPluginName: b.pluginName,
|
|
4616
|
+
backupTime: b.backupTime
|
|
4617
|
+
}));
|
|
4618
|
+
}
|
|
4619
|
+
if (preservedTargets.length > 0) {
|
|
4620
|
+
record.preservedTargets = [...preservedTargets];
|
|
4435
4621
|
}
|
|
4436
4622
|
writeRecord(record);
|
|
4437
4623
|
} catch {
|
|
@@ -4519,16 +4705,21 @@ async function installPlugin(opts) {
|
|
|
4519
4705
|
cwd,
|
|
4520
4706
|
configRoot,
|
|
4521
4707
|
manifest,
|
|
4522
|
-
plugin.externalRepos?.map((r) =>
|
|
4523
|
-
plugin.configRootConfigLink
|
|
4708
|
+
plugin.externalRepos?.map((r) => basename3(r.dir)),
|
|
4709
|
+
plugin.configRootConfigLink,
|
|
4710
|
+
preservedTargets
|
|
4524
4711
|
);
|
|
4525
|
-
if (
|
|
4526
|
-
record.
|
|
4527
|
-
filePath:
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4712
|
+
if (backups.length > 0) {
|
|
4713
|
+
record.backups = backups.map((b) => ({
|
|
4714
|
+
filePath: b.filePath,
|
|
4715
|
+
originalPath: b.originalPath,
|
|
4716
|
+
fromPluginId: b.pluginId,
|
|
4717
|
+
fromPluginName: b.pluginName,
|
|
4718
|
+
backupTime: b.backupTime
|
|
4719
|
+
}));
|
|
4720
|
+
}
|
|
4721
|
+
if (preservedTargets.length > 0) {
|
|
4722
|
+
record.preservedTargets = [...preservedTargets];
|
|
4532
4723
|
}
|
|
4533
4724
|
writeRecord(record);
|
|
4534
4725
|
} catch {
|
|
@@ -4650,7 +4841,7 @@ function installerSupportsBundledFlag() {
|
|
|
4650
4841
|
}
|
|
4651
4842
|
async function delegateInstall(options) {
|
|
4652
4843
|
const { pluginId, tool, level } = options;
|
|
4653
|
-
const target =
|
|
4844
|
+
const target = resolve4(options.target || process.cwd());
|
|
4654
4845
|
const displayName = options.displayName || pluginId;
|
|
4655
4846
|
const result = {
|
|
4656
4847
|
success: false,
|
|
@@ -4776,8 +4967,8 @@ init_fs_helpers();
|
|
|
4776
4967
|
init_constants();
|
|
4777
4968
|
init_logger();
|
|
4778
4969
|
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
|
|
4970
|
+
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";
|
|
4971
|
+
import { join as join17, dirname as dirname8, basename as basename4, isAbsolute as isAbsolute2 } from "path";
|
|
4781
4972
|
import { select as select3, checkbox, Separator as Separator2 } from "@inquirer/prompts";
|
|
4782
4973
|
import chalk5 from "chalk";
|
|
4783
4974
|
import Table from "cli-table3";
|
|
@@ -4805,7 +4996,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
4805
4996
|
continue;
|
|
4806
4997
|
}
|
|
4807
4998
|
try {
|
|
4808
|
-
const resolvedSource =
|
|
4999
|
+
const resolvedSource = realpathSync3(sourcePath);
|
|
4809
5000
|
if (isSymlink(targetPath)) {
|
|
4810
5001
|
try {
|
|
4811
5002
|
const currentTarget = readlinkSync2(targetPath);
|
|
@@ -4884,11 +5075,11 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
4884
5075
|
rmSync5(skillsDir, { recursive: true });
|
|
4885
5076
|
logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
|
|
4886
5077
|
if (tool === "codex") {
|
|
4887
|
-
const agentsRoot =
|
|
5078
|
+
const agentsRoot = dirname8(skillsDir);
|
|
4888
5079
|
try {
|
|
4889
5080
|
if (existsSync18(agentsRoot) && readdirSync9(agentsRoot).length === 0) {
|
|
4890
5081
|
rmSync5(agentsRoot, { recursive: true });
|
|
4891
|
-
logger.step(` ${t("uninstall_clean_empty_dir")}: ${
|
|
5082
|
+
logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename4(agentsRoot)}/`);
|
|
4892
5083
|
}
|
|
4893
5084
|
} catch {
|
|
4894
5085
|
}
|
|
@@ -5298,7 +5489,7 @@ function resolveSkillSourcePath(skill, repoPath) {
|
|
|
5298
5489
|
if (skill.filePath) {
|
|
5299
5490
|
const absPath = isAbsolute2(skill.filePath) ? skill.filePath : join17(repoPath, skill.filePath);
|
|
5300
5491
|
if (existsSync18(absPath)) {
|
|
5301
|
-
return
|
|
5492
|
+
return dirname8(absPath);
|
|
5302
5493
|
}
|
|
5303
5494
|
}
|
|
5304
5495
|
return join17(repoPath, skill.source, skill.id);
|
|
@@ -6354,7 +6545,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
|
|
|
6354
6545
|
// src/commands/uninstall.ts
|
|
6355
6546
|
init_registry();
|
|
6356
6547
|
import { existsSync as existsSync21, unlinkSync as unlinkSync8, rmdirSync as rmdirSync2, readdirSync as readdirSync11, readFileSync as readFileSync15 } from "fs";
|
|
6357
|
-
import { resolve as
|
|
6548
|
+
import { resolve as resolve5, basename as basename5, sep as sep3, join as join20 } from "path";
|
|
6358
6549
|
import chalk11 from "chalk";
|
|
6359
6550
|
import { select as select5, checkbox as checkbox2, Separator as Separator4, confirm as confirm3 } from "@inquirer/prompts";
|
|
6360
6551
|
init_config();
|
|
@@ -6740,7 +6931,7 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6740
6931
|
installPath,
|
|
6741
6932
|
configRoot2,
|
|
6742
6933
|
manifest,
|
|
6743
|
-
plugin.externalRepos?.map((r) =>
|
|
6934
|
+
plugin.externalRepos?.map((r) => basename5(r.dir)),
|
|
6744
6935
|
plugin.configRootConfigLink
|
|
6745
6936
|
);
|
|
6746
6937
|
break;
|
|
@@ -6755,14 +6946,15 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6755
6946
|
}
|
|
6756
6947
|
logger.info(`${t("uninstall_in_progress")} ${plugin.displayName}...`);
|
|
6757
6948
|
const configRoot = record.configRoot;
|
|
6758
|
-
const allowedBases = [
|
|
6949
|
+
const allowedBases = [resolve5(configRoot), resolve5(record.installPath)];
|
|
6759
6950
|
if (record.tool === "codex") {
|
|
6760
|
-
allowedBases.push(
|
|
6951
|
+
allowedBases.push(resolve5(getSkillsRoot(record.tool, record.level, record.installPath)));
|
|
6761
6952
|
}
|
|
6762
6953
|
const isSafePath = (p) => {
|
|
6763
|
-
const resolved =
|
|
6954
|
+
const resolved = resolve5(p);
|
|
6764
6955
|
return allowedBases.some((base) => resolved === base || resolved.startsWith(base + sep3));
|
|
6765
6956
|
};
|
|
6957
|
+
const preservedPaths = new Set((record.preservedTargets || []).map((p) => resolve5(p)));
|
|
6766
6958
|
let removedFiles = 0;
|
|
6767
6959
|
let removedDirs = 0;
|
|
6768
6960
|
const configFileName = record.tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
@@ -6772,13 +6964,15 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6772
6964
|
if (record.level === "project" && configRootConfigPath !== installPathConfigPath && !record.files.includes(configRootConfigPath) && (existsSync21(configRootConfigPath) || isSymlink(configRootConfigPath))) {
|
|
6773
6965
|
extraFiles.push(configRootConfigPath);
|
|
6774
6966
|
}
|
|
6775
|
-
const allFiles = [...record.files, ...extraFiles]
|
|
6967
|
+
const allFiles = [...record.files, ...extraFiles].filter(
|
|
6968
|
+
(filePath) => !preservedPaths.has(resolve5(filePath))
|
|
6969
|
+
);
|
|
6776
6970
|
for (const filePath of allFiles) {
|
|
6777
6971
|
if (!isSafePath(filePath)) continue;
|
|
6778
6972
|
try {
|
|
6779
6973
|
if (existsSync21(filePath) || isSymlink(filePath)) {
|
|
6780
6974
|
unlinkSync8(filePath);
|
|
6781
|
-
const name =
|
|
6975
|
+
const name = basename5(filePath);
|
|
6782
6976
|
logger.step(` ${t("uninstall_remove_label")}: ${name}`);
|
|
6783
6977
|
removedFiles++;
|
|
6784
6978
|
}
|
|
@@ -6788,14 +6982,14 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6788
6982
|
const sortedDirs = [...record.directories].filter(isSafePath).sort((a, b) => b.length - a.length);
|
|
6789
6983
|
for (const dirPath of sortedDirs) {
|
|
6790
6984
|
try {
|
|
6791
|
-
if (
|
|
6985
|
+
if (resolve5(dirPath) === resolve5(configRoot)) {
|
|
6792
6986
|
continue;
|
|
6793
6987
|
}
|
|
6794
6988
|
if (existsSync21(dirPath)) {
|
|
6795
6989
|
const entries = readdirSync11(dirPath);
|
|
6796
6990
|
if (entries.length === 0) {
|
|
6797
6991
|
rmdirSync2(dirPath);
|
|
6798
|
-
const name =
|
|
6992
|
+
const name = basename5(dirPath);
|
|
6799
6993
|
logger.step(` ${t("uninstall_clean_empty_dir")}: ${name}/`);
|
|
6800
6994
|
removedDirs++;
|
|
6801
6995
|
}
|
|
@@ -6805,10 +6999,10 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6805
6999
|
}
|
|
6806
7000
|
if (record.tool === "codex") {
|
|
6807
7001
|
try {
|
|
6808
|
-
const agentsRoot =
|
|
7002
|
+
const agentsRoot = resolve5(getSkillsRoot(record.tool, record.level, record.installPath), "..");
|
|
6809
7003
|
if (existsSync21(agentsRoot) && readdirSync11(agentsRoot).length === 0) {
|
|
6810
7004
|
rmdirSync2(agentsRoot);
|
|
6811
|
-
logger.step(` ${t("uninstall_clean_empty_dir")}: ${
|
|
7005
|
+
logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename5(agentsRoot)}/`);
|
|
6812
7006
|
removedDirs++;
|
|
6813
7007
|
}
|
|
6814
7008
|
} catch {
|
|
@@ -6820,16 +7014,27 @@ async function uninstallPluginById(pluginId, batchMode) {
|
|
|
6820
7014
|
installPath: record.installPath
|
|
6821
7015
|
});
|
|
6822
7016
|
removeInstalledPlugin(plugin.id);
|
|
6823
|
-
const
|
|
7017
|
+
const backupDirs = resolve5(record.installPath) === resolve5(configRoot) ? [configRoot] : [configRoot, record.installPath];
|
|
7018
|
+
const recordBackups = [
|
|
7019
|
+
...record.backups || [],
|
|
7020
|
+
...record.backup ? [{ ...record.backup, originalPath: join20(configRoot, configFileName) }] : []
|
|
7021
|
+
];
|
|
7022
|
+
const backups = findBackups(backupDirs).map((b) => {
|
|
7023
|
+
const recorded = recordBackups.find((rb) => resolve5(rb.filePath) === resolve5(b.filePath));
|
|
7024
|
+
return recorded ? { ...b, originalPath: recorded.originalPath } : b;
|
|
7025
|
+
});
|
|
6824
7026
|
const otherBackups = backups.filter((b) => b.pluginId !== pluginId);
|
|
6825
7027
|
if (!batchMode && otherBackups.length > 0) {
|
|
6826
7028
|
const choice = await showRestorePrompt(otherBackups);
|
|
6827
7029
|
if (choice !== "none") {
|
|
6828
|
-
const
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
7030
|
+
const backupInfo = otherBackups.find((b) => b.filePath === choice);
|
|
7031
|
+
const restoreTarget = backupInfo?.originalPath || join20(configRoot, configFileName);
|
|
7032
|
+
if (isSafePath(restoreTarget)) {
|
|
7033
|
+
const restored = restoreBackup(choice, restoreTarget);
|
|
7034
|
+
if (restored) {
|
|
7035
|
+
logger.success(`${t("backup_restore_success")}: ${backupInfo?.pluginName || ""} -> ${restoreTarget}`);
|
|
7036
|
+
deleteBackup(choice);
|
|
7037
|
+
}
|
|
6833
7038
|
}
|
|
6834
7039
|
}
|
|
6835
7040
|
} else if (batchMode && otherBackups.length > 0) {
|
|
@@ -7101,7 +7306,7 @@ init_config();
|
|
|
7101
7306
|
init_i18n();
|
|
7102
7307
|
import { readFileSync as readFileSync16, existsSync as existsSync23 } from "fs";
|
|
7103
7308
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7104
|
-
import { dirname as
|
|
7309
|
+
import { dirname as dirname9, join as join22 } from "path";
|
|
7105
7310
|
function readVersion() {
|
|
7106
7311
|
try {
|
|
7107
7312
|
if (typeof INSTALL_HELPER_VERSION !== "undefined" && INSTALL_HELPER_VERSION) {
|
|
@@ -7111,7 +7316,7 @@ function readVersion() {
|
|
|
7111
7316
|
}
|
|
7112
7317
|
try {
|
|
7113
7318
|
const __filename5 = fileURLToPath5(import.meta.url);
|
|
7114
|
-
const __dirname5 =
|
|
7319
|
+
const __dirname5 = dirname9(__filename5);
|
|
7115
7320
|
const candidates = [
|
|
7116
7321
|
join22(__dirname5, "..", "package.json"),
|
|
7117
7322
|
join22(__dirname5, "package.json"),
|