@cannbot-ai/install-helper 1.2.0 → 1.2.1-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 CHANGED
@@ -101,18 +101,18 @@ install-helper install --list # 查看所有可用 Sk
101
101
  |------|------|
102
102
  | `--tool <tool>` | 指定 AI 工具(opencode, claude, trae, cursor, codex, copilot, codearts) |
103
103
  | `--level <level>` | 安装级别(project, global),默认 project |
104
- | `--source <source>` | 同名插件的安装来源(cannbot, skills):默认 cannbot 仓新代实现优先,`--source skills` 强制安装本仓旧版 |
104
+ | `--source <source>` | 同名插件的安装来源(cannbot, skills):默认 cannbot 仓插件优先,`--source skills` 强制安装 cannbot-skills 仓旧版 |
105
105
  | `--all` `-a` | 安装全部 Skills |
106
106
  | `--list` | 按类别列出所有可用 Skills |
107
107
  | `--yes` `-y` | 跳过所有确认提示 |
108
108
 
109
- ### 安装 cannbot 仓新一代插件(双源)
109
+ ### 安装 cannbot 仓插件(双源)
110
110
 
111
- 插件编排已拆分至 [cannbot 仓](https://gitcode.com/cann/cannbot)(`ops-direct-invoke` v3、`ascendc-st-design`、`model-infer-optimize`、`ops-registry-invoke` 等新一代插件)。install-helper 以**委托转发**方式兼容其安装方式:自动托管 `@cannbot-plugin/cannbot` 安装器(npm 拉取到 `~/.cannbot/installers/cannbot`,按通道 + TTL 自动刷新),安装时委托其执行,产物布局(`.agents/skills`、标记块 AGENTS.md、`.cannbot/plugins/` 资产、`cannbot-plugin.json` 注册表)与 `npx @cannbot-plugin/cannbot install` 直装**完全一致**。
111
+ 插件编排已拆分至 [cannbot 仓](https://gitcode.com/cann/cannbot)(`ops-direct-invoke` v3、`ascendc-st-design`、`model-infer-optimize`、`ops-registry-invoke` 等 cannbot 仓插件)。install-helper 以**委托转发**方式兼容其安装方式:自动托管 `@cannbot-plugin/cannbot` 安装器(npm 拉取到 `~/.cannbot/installers/cannbot`,按通道 + TTL 自动刷新),安装时委托其执行,产物布局(`.agents/skills`、标记块 AGENTS.md、`.cannbot/plugins/` 资产、`cannbot-plugin.json` 注册表)与 `npx @cannbot-plugin/cannbot install` 直装**完全一致**。
112
112
 
113
113
  ```bash
114
- install-helper install ops-direct-invoke --tool opencode # cannbot 新代实现(默认)
115
- install-helper install ops-direct-invoke --source skills --tool opencode # 本仓旧版
114
+ install-helper install ops-direct-invoke --tool opencode # cannbot 仓插件(默认)
115
+ install-helper install ops-direct-invoke --source skills --tool opencode # cannbot-skills 仓旧版
116
116
  install-helper update ops-direct-invoke # 更新 = 重新委托安装
117
117
  install-helper uninstall ops-direct-invoke # 按 cannbot-plugin.json 注册表精确卸载
118
118
  ```
@@ -28,7 +28,7 @@ pluginDirs:
28
28
 
29
29
  scanCacheTtlHours: 24
30
30
 
31
- # cannbot 仓(https://gitcode.com/cann/cannbot)新一代插件的安装器托管配置。
31
+ # cannbot 仓(https://gitcode.com/cann/cannbot)插件的安装器托管配置。
32
32
  # install-helper 以委托转发方式安装 cannbot 型插件:按通道将
33
33
  # @cannbot-plugin/cannbot 安装到 ~/.cannbot/installers/cannbot,
34
34
  # 超过 ttlHours 后自动按通道刷新。
package/dist/index.js CHANGED
@@ -112,6 +112,7 @@ var init_zh_CN = __esm({
112
112
  error_skill_not_found: "\u672A\u5728\u6CE8\u518C\u8868\u4E2D\u627E\u5230 Skill",
113
113
  error_source_not_found: "\u672A\u627E\u5230\u6E90\u6587\u4EF6: {path}",
114
114
  error_script_not_found: "\u672A\u627E\u5230\u5B89\u88C5\u811A\u672C: {path}",
115
+ error_cannbot_requires_delegation: "\u63D2\u4EF6 {plugin} \u4E3A cannbot \u4ED3\u59D4\u6258\u5B89\u88C5\u6E90\uFF0C\u987B\u7ECF installPluginRouted \u8DEF\u7531\u5B89\u88C5\uFF08\u5185\u90E8\u8DEF\u7531\u9519\u8BEF\uFF0C\u8BF7\u63D0 Issue \u53CD\u9988\uFF09",
115
116
  error_unknown: "\u672A\u77E5\u9519\u8BEF",
116
117
  error_not_installed: "\u672A\u5B89\u88C5",
117
118
  error_no_shell: "\u672A\u627E\u5230 bash \u6216 sh\uFF0C\u65E0\u6CD5\u6267\u884C\u5B89\u88C5\u811A\u672C\u3002\u8BF7\u5B89\u88C5 Git Bash \u6216 WSL",
@@ -363,6 +364,7 @@ var init_en_US = __esm({
363
364
  error_skill_not_found: "Skill not found in registry",
364
365
  error_source_not_found: "Source not found: {path}",
365
366
  error_script_not_found: "Script not found: {path}",
367
+ error_cannbot_requires_delegation: "Plugin {plugin} is a cannbot-source entry and must be installed via installPluginRouted delegation (internal routing error \u2014 please report an issue)",
366
368
  error_unknown: "Unknown error",
367
369
  error_not_installed: "Not installed",
368
370
  error_no_shell: "bash or sh not found, cannot execute install script. Please install Git Bash or WSL",
@@ -2911,7 +2913,7 @@ function createRepositoryManager(customPath) {
2911
2913
 
2912
2914
  // src/core/cannbot-delegate.ts
2913
2915
  import { existsSync as existsSync17, readFileSync as readFileSync12, writeFileSync as writeFileSync5, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6, readdirSync as readdirSync8 } from "fs";
2914
- import { join as join16, resolve as resolve2 } from "path";
2916
+ import { join as join16, resolve as resolve3 } from "path";
2915
2917
  import { execa as execa6 } from "execa";
2916
2918
 
2917
2919
  // src/core/cannbot-installer.ts
@@ -3152,7 +3154,7 @@ async function ensureCannbotDiscovery() {
3152
3154
 
3153
3155
  // src/core/cannbot-registry.ts
3154
3156
  import { existsSync as existsSync13, readFileSync as readFileSync9, readdirSync as readdirSync6, rmSync as rmSync3, rmdirSync, unlinkSync as unlinkSync4, lstatSync as lstatSync2, writeFileSync as writeFileSync3 } from "fs";
3155
- import { join as join12, resolve, sep as sep2, dirname as dirname6 } from "path";
3157
+ import { join as join12, resolve as resolve2, sep as sep2, dirname as dirname6 } from "path";
3156
3158
 
3157
3159
  // src/core/record.ts
3158
3160
  init_paths();
@@ -3161,38 +3163,88 @@ init_fs_helpers();
3161
3163
  init_logger();
3162
3164
  init_i18n();
3163
3165
  import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync5 } from "fs";
3164
- import { join as join11 } from "path";
3166
+ import { join as join11, resolve } from "path";
3167
+ var LEGACY_LOCATION_KEY = "__legacy__";
3165
3168
  function getInstallsDir() {
3166
3169
  return join11(getCannbotConfigDir(), "installs");
3167
3170
  }
3168
3171
  function getRecordPath(pluginId) {
3169
3172
  return join11(getInstallsDir(), `${pluginId}.json`);
3170
3173
  }
3171
- function readRecord(pluginId) {
3174
+ function locationKey(loc) {
3175
+ return `${loc.tool}:${loc.level}:${resolve(loc.installPath)}`;
3176
+ }
3177
+ function readStore(pluginId) {
3172
3178
  const recordPath = getRecordPath(pluginId);
3173
3179
  if (!existsSync12(recordPath)) {
3174
3180
  return null;
3175
3181
  }
3182
+ let parsed;
3176
3183
  try {
3177
- const content = readFileSync8(recordPath, "utf-8");
3178
- return JSON.parse(content);
3184
+ parsed = JSON.parse(readFileSync8(recordPath, "utf-8"));
3179
3185
  } catch {
3180
3186
  logger.warn(t("record_corrupted").replace("{file}", recordPath));
3181
3187
  return null;
3182
3188
  }
3189
+ const store = parsed;
3190
+ if (store && typeof store === "object" && "locations" in store && store.locations) {
3191
+ return { version: 2, locations: store.locations };
3192
+ }
3193
+ const legacy = parsed;
3194
+ if (legacy && typeof legacy === "object" && typeof legacy.pluginId === "string") {
3195
+ const key = legacy.tool && legacy.level && legacy.installPath ? locationKey(legacy) : LEGACY_LOCATION_KEY;
3196
+ return { version: 2, locations: { [key]: legacy } };
3197
+ }
3198
+ logger.warn(t("record_corrupted").replace("{file}", recordPath));
3199
+ return null;
3183
3200
  }
3184
- function writeRecord(record) {
3201
+ function writeStore(pluginId, store) {
3185
3202
  const installsDir = getInstallsDir();
3186
3203
  if (!existsSync12(installsDir)) {
3187
3204
  mkdirSync5(installsDir, { recursive: true });
3188
3205
  }
3189
- const recordPath = getRecordPath(record.pluginId);
3190
- atomicWriteFileSync(recordPath, JSON.stringify(record, null, 2));
3206
+ atomicWriteFileSync(getRecordPath(pluginId), JSON.stringify(store, null, 2));
3191
3207
  }
3192
- function deleteRecord(pluginId) {
3208
+ function readRecords(pluginId) {
3209
+ const store = readStore(pluginId);
3210
+ return store ? Object.values(store.locations) : [];
3211
+ }
3212
+ var byLatest = (a, b) => (b.installTime || "").localeCompare(a.installTime || "");
3213
+ function readRecord(pluginId) {
3214
+ const records = readRecords(pluginId);
3215
+ if (records.length === 0) {
3216
+ return null;
3217
+ }
3218
+ const cwd = resolve(process.cwd());
3219
+ const localMatch = records.filter((r) => r.level === "project" && resolve(r.installPath) === cwd).sort(byLatest);
3220
+ if (localMatch.length > 0) return localMatch[0];
3221
+ const globalMatch = records.filter((r) => r.level === "global").sort(byLatest);
3222
+ if (globalMatch.length > 0) return globalMatch[0];
3223
+ return [...records].sort(byLatest)[0];
3224
+ }
3225
+ function writeRecord(record) {
3226
+ const store = readStore(record.pluginId) ?? { version: 2, locations: {} };
3227
+ store.locations[locationKey(record)] = record;
3228
+ writeStore(record.pluginId, store);
3229
+ }
3230
+ function deleteRecord(pluginId, where) {
3193
3231
  const recordPath = getRecordPath(pluginId);
3194
- if (existsSync12(recordPath)) {
3232
+ if (!existsSync12(recordPath)) {
3233
+ return;
3234
+ }
3235
+ if (!where) {
3236
+ unlinkSync3(recordPath);
3237
+ return;
3238
+ }
3239
+ const store = readStore(pluginId);
3240
+ if (!store) {
3241
+ return;
3242
+ }
3243
+ delete store.locations[locationKey(where)];
3244
+ if (Object.keys(store.locations).length === 0) {
3195
3245
  unlinkSync3(recordPath);
3246
+ } else {
3247
+ writeStore(pluginId, store);
3196
3248
  }
3197
3249
  }
3198
3250
  function scanInstalledFiles(pluginId, displayName, tool, level, installPath, configRoot, manifest, externalRepoNames, configRootConfigLink) {
@@ -3443,7 +3495,7 @@ function toInstalledEntry(target, registryPath, record) {
3443
3495
  };
3444
3496
  }
3445
3497
  function scanCannbotInstalled(target) {
3446
- const root = resolve(target || process.cwd());
3498
+ const root = resolve2(target || process.cwd());
3447
3499
  const installed = [];
3448
3500
  for (const tool of CANNBOT_SUPPORTED_TOOLS) {
3449
3501
  const result = readCannbotRegistry(root, tool);
@@ -3469,7 +3521,7 @@ function countMarkerBlocks(content, pluginName) {
3469
3521
  return content.split(start).length - 1;
3470
3522
  }
3471
3523
  function removeIfSafe(pathToRemove, allowedBase) {
3472
- const resolved = resolve(pathToRemove);
3524
+ const resolved = resolve2(pathToRemove);
3473
3525
  if (resolved !== allowedBase && !resolved.startsWith(allowedBase + sep2)) {
3474
3526
  return "skipped";
3475
3527
  }
@@ -3486,8 +3538,8 @@ function removeIfSafe(pathToRemove, allowedBase) {
3486
3538
  }
3487
3539
  }
3488
3540
  function removeEmptyDirUpward(dirPath, stopAt) {
3489
- let current = resolve(dirPath);
3490
- const stop = resolve(stopAt);
3541
+ let current = resolve2(dirPath);
3542
+ const stop = resolve2(stopAt);
3491
3543
  let removedAny = false;
3492
3544
  while (current.startsWith(stop + sep2)) {
3493
3545
  try {
@@ -3503,7 +3555,7 @@ function removeEmptyDirUpward(dirPath, stopAt) {
3503
3555
  return removedAny;
3504
3556
  }
3505
3557
  function cleanHookSettings(hookSettingsPath, target, pluginId) {
3506
- const resolved = resolve(target, hookSettingsPath);
3558
+ const resolved = resolve2(target, hookSettingsPath);
3507
3559
  if (!existsSync13(resolved)) return;
3508
3560
  let settings;
3509
3561
  try {
@@ -3616,7 +3668,7 @@ function uninstallCannbotPlugin(pluginId, target) {
3616
3668
  removedDirs: 0,
3617
3669
  errors: []
3618
3670
  };
3619
- const root = resolve(target || process.cwd());
3671
+ const root = resolve2(target || process.cwd());
3620
3672
  let read = null;
3621
3673
  let record;
3622
3674
  for (const tool of CANNBOT_SUPPORTED_TOOLS) {
@@ -3650,7 +3702,7 @@ function uninstallCannbotPlugin(pluginId, target) {
3650
3702
  }
3651
3703
  if (record.instructions) {
3652
3704
  const instructionsPath = join12(root, record.instructions);
3653
- const resolved = resolve(instructionsPath);
3705
+ const resolved = resolve2(instructionsPath);
3654
3706
  if (resolved.startsWith(allowedBase + sep2) && existsSync13(resolved)) {
3655
3707
  try {
3656
3708
  const content = readFileSync9(resolved, "utf-8");
@@ -3734,16 +3786,21 @@ function uninstallCannbotPlugin(pluginId, target) {
3734
3786
  }
3735
3787
  function findOrphanedDelegatedRecords(target) {
3736
3788
  const orphans = [];
3737
- const installed = new Set(scanCannbotInstalled(target).map((e) => e.id));
3738
3789
  const installsDir = join12(getCannbotConfigDir(), "installs");
3739
3790
  if (!existsSync13(installsDir)) return orphans;
3740
3791
  for (const file of readdirSync6(installsDir)) {
3741
3792
  if (!file.endsWith(".json") || file === "skills.json") continue;
3742
3793
  const pluginId = file.replace(/\.json$/, "");
3743
3794
  try {
3744
- const rec = JSON.parse(readFileSync9(join12(installsDir, file), "utf-8"));
3745
- if (rec?.kind !== "delegated") continue;
3746
- if (!installed.has(pluginId)) {
3795
+ const records = readRecords(pluginId);
3796
+ const delegated = records.filter((r) => r?.kind === "delegated");
3797
+ if (delegated.length === 0) continue;
3798
+ const isOrphan = delegated.some((rec) => {
3799
+ const recTarget = rec.installPath || target;
3800
+ const installedThere = new Set(scanCannbotInstalled(recTarget).map((e) => e.id));
3801
+ return !installedThere.has(pluginId);
3802
+ });
3803
+ if (isOrphan) {
3747
3804
  orphans.push(pluginId);
3748
3805
  }
3749
3806
  } catch {
@@ -3757,7 +3814,7 @@ init_registry();
3757
3814
  init_manifest();
3758
3815
  init_paths();
3759
3816
  import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
3760
- import { join as join15, basename as basename2 } from "path";
3817
+ import { join as join15, basename as basename2, isAbsolute } from "path";
3761
3818
  import { execa as execa5, execaSync as execaSync2 } from "execa";
3762
3819
 
3763
3820
  // src/core/backup.ts
@@ -3884,10 +3941,7 @@ function readAllRecords() {
3884
3941
  const records = [];
3885
3942
  const plugins = getAllPlugins();
3886
3943
  for (const plugin of plugins) {
3887
- const record = readRecord(plugin.id);
3888
- if (record) {
3889
- records.push(record);
3890
- }
3944
+ records.push(...readRecords(plugin.id));
3891
3945
  }
3892
3946
  return records;
3893
3947
  }
@@ -4281,7 +4335,7 @@ function scriptSupportsTool(scriptPath, tool) {
4281
4335
  }
4282
4336
  }
4283
4337
  async function installPlugin(opts) {
4284
- const plugin = getPluginById(opts.pluginId);
4338
+ const plugin = opts.plugin ?? getPluginById(opts.pluginId);
4285
4339
  if (!plugin) {
4286
4340
  return {
4287
4341
  success: false,
@@ -4292,7 +4346,17 @@ async function installPlugin(opts) {
4292
4346
  warnings: []
4293
4347
  };
4294
4348
  }
4295
- const pluginDir = join15(opts.repoPath, plugin.dir);
4349
+ if (plugin.source === "cannbot") {
4350
+ return {
4351
+ success: false,
4352
+ pluginId: opts.pluginId,
4353
+ skillsCount: 0,
4354
+ agentsCount: 0,
4355
+ errors: [t("error_cannbot_requires_delegation").replace("{plugin}", plugin.displayName)],
4356
+ warnings: []
4357
+ };
4358
+ }
4359
+ const pluginDir = isAbsolute(plugin.dir) ? plugin.dir : join15(opts.repoPath, plugin.dir);
4296
4360
  const cwd = opts.installPath || process.cwd();
4297
4361
  const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
4298
4362
  const agentsFile = join15(configRoot, getAgentsFileName(opts.tool));
@@ -4586,7 +4650,7 @@ function installerSupportsBundledFlag() {
4586
4650
  }
4587
4651
  async function delegateInstall(options) {
4588
4652
  const { pluginId, tool, level } = options;
4589
- const target = resolve2(options.target || process.cwd());
4653
+ const target = resolve3(options.target || process.cwd());
4590
4654
  const displayName = options.displayName || pluginId;
4591
4655
  const result = {
4592
4656
  success: false,
@@ -4713,7 +4777,7 @@ init_constants();
4713
4777
  init_logger();
4714
4778
  init_i18n();
4715
4779
  import { existsSync as existsSync18, mkdirSync as mkdirSync7, symlinkSync as symlinkSync2, readdirSync as readdirSync9, rmSync as rmSync5, realpathSync as realpathSync2, readlinkSync as readlinkSync2, cpSync as cpSync2 } from "fs";
4716
- import { join as join17, dirname as dirname7, basename as basename3, isAbsolute } from "path";
4780
+ import { join as join17, dirname as dirname7, basename as basename3, isAbsolute as isAbsolute2 } from "path";
4717
4781
  import { select as select3, checkbox, Separator as Separator2 } from "@inquirer/prompts";
4718
4782
  import chalk5 from "chalk";
4719
4783
  import Table from "cli-table3";
@@ -5232,7 +5296,7 @@ function listAllSkills() {
5232
5296
  }
5233
5297
  function resolveSkillSourcePath(skill, repoPath) {
5234
5298
  if (skill.filePath) {
5235
- const absPath = isAbsolute(skill.filePath) ? skill.filePath : join17(repoPath, skill.filePath);
5299
+ const absPath = isAbsolute2(skill.filePath) ? skill.filePath : join17(repoPath, skill.filePath);
5236
5300
  if (existsSync18(absPath)) {
5237
5301
  return dirname7(absPath);
5238
5302
  }
@@ -5319,7 +5383,9 @@ function printEnhancedSummary(results, tool, configRoot) {
5319
5383
  ""
5320
5384
  ];
5321
5385
  if (successResults.length === 1) {
5322
- const plugin = findPlugin(successResults[0].pluginId);
5386
+ const plugin = findPlugin(successResults[0].pluginId, {
5387
+ source: successResults[0].source
5388
+ });
5323
5389
  const docsPath = plugin ? `${plugin.dir}/quickstart.md` : `${successResults[0].pluginId}/quickstart.md`;
5324
5390
  lines.push(
5325
5391
  ` ${chalk6.dim(t("install_enhanced_docs"))}: ${chalk6.dim(docsPath)}`
@@ -5487,7 +5553,8 @@ async function pluginInstallFlow() {
5487
5553
  displayName: selected[index]?.plugin?.displayName || result.pluginId,
5488
5554
  success: result.success,
5489
5555
  skillsCount: result.skillsCount,
5490
- agentsCount: result.agentsCount
5556
+ agentsCount: result.agentsCount,
5557
+ source: selected[index]?.source
5491
5558
  }));
5492
5559
  printInstallSummary(summary);
5493
5560
  const configRoot = getConfigRoot(answers.tool, answers.level);
@@ -6087,6 +6154,9 @@ async function installCommand(names, options) {
6087
6154
  logger.info(`${t("install_to")}: ${chalk10.cyan(getSkillsRoot(tool2, level2))}`);
6088
6155
  logger.info(`${t("start_to_use").replace("{tool}", chalk10.green(tool2))}`);
6089
6156
  logger.blank();
6157
+ if (failCount > 0) {
6158
+ process.exitCode = 1;
6159
+ }
6090
6160
  return;
6091
6161
  }
6092
6162
  }
@@ -6123,6 +6193,7 @@ async function installCommand(names, options) {
6123
6193
  logger.step(` ${p.id}${badge} (${p.aliases.join(", ")})`);
6124
6194
  }
6125
6195
  logger.info(`${t("available_skills")}: ${chalk10.cyan("install-helper install --list")}`);
6196
+ process.exitCode = 1;
6126
6197
  return;
6127
6198
  }
6128
6199
  let tool;
@@ -6176,7 +6247,6 @@ async function installCommand(names, options) {
6176
6247
  spinner.fail(t("repo_clone_failed").replace("{error}", error instanceof Error ? error.message : t("error_unknown")).replace("{url}", "").replace("{dir}", ""));
6177
6248
  return;
6178
6249
  }
6179
- const allPlugins = getAllPlugins();
6180
6250
  const results = await installPlugins(
6181
6251
  pluginsToInstall,
6182
6252
  tool,
@@ -6187,17 +6257,21 @@ async function installCommand(names, options) {
6187
6257
  source
6188
6258
  );
6189
6259
  const summary = results.map((result) => {
6190
- const plugin = allPlugins.find((p) => p.id === result.pluginId);
6260
+ const plugin = findPlugin(result.pluginId, { source });
6191
6261
  return {
6192
6262
  pluginId: result.pluginId,
6193
6263
  displayName: plugin?.displayName || result.pluginId,
6194
6264
  success: result.success,
6195
6265
  skillsCount: result.skillsCount,
6196
- agentsCount: result.agentsCount
6266
+ agentsCount: result.agentsCount,
6267
+ source: plugin?.source
6197
6268
  };
6198
6269
  });
6199
6270
  printInstallSummary(summary);
6200
6271
  printEnhancedSummary(summary, tool, configRoot);
6272
+ if (results.some((r) => !r.success)) {
6273
+ process.exitCode = 1;
6274
+ }
6201
6275
  }
6202
6276
  }
6203
6277
  if (skills.length > 0) {
@@ -6234,6 +6308,9 @@ async function installCommand(names, options) {
6234
6308
  logger.info(`${t("install_to")}: ${chalk10.cyan(getSkillsRoot(tool, level))}`);
6235
6309
  logger.info(`${t("start_to_use").replace("{tool}", chalk10.green(tool))}`);
6236
6310
  logger.blank();
6311
+ if (failCount > 0) {
6312
+ process.exitCode = 1;
6313
+ }
6237
6314
  }
6238
6315
  }
6239
6316
  async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes, source) {
@@ -6274,7 +6351,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
6274
6351
  // src/commands/uninstall.ts
6275
6352
  init_registry();
6276
6353
  import { existsSync as existsSync21, unlinkSync as unlinkSync8, rmdirSync as rmdirSync2, readdirSync as readdirSync11, readFileSync as readFileSync15 } from "fs";
6277
- import { resolve as resolve3, basename as basename4, sep as sep3, join as join20 } from "path";
6354
+ import { resolve as resolve4, basename as basename4, sep as sep3, join as join20 } from "path";
6278
6355
  import chalk11 from "chalk";
6279
6356
  import { select as select5, checkbox as checkbox2, Separator as Separator4, confirm as confirm3 } from "@inquirer/prompts";
6280
6357
  init_config();
@@ -6674,13 +6751,13 @@ async function uninstallPluginById(pluginId, batchMode) {
6674
6751
  return;
6675
6752
  }
6676
6753
  logger.info(`${t("uninstall_in_progress")} ${plugin.displayName}...`);
6677
- const configRoot = getConfigRoot(record.tool, record.level);
6678
- const allowedBases = [resolve3(configRoot), resolve3(record.installPath)];
6754
+ const configRoot = record.configRoot;
6755
+ const allowedBases = [resolve4(configRoot), resolve4(record.installPath)];
6679
6756
  if (record.tool === "codex") {
6680
- allowedBases.push(resolve3(getSkillsRoot(record.tool, record.level, record.installPath)));
6757
+ allowedBases.push(resolve4(getSkillsRoot(record.tool, record.level, record.installPath)));
6681
6758
  }
6682
6759
  const isSafePath = (p) => {
6683
- const resolved = resolve3(p);
6760
+ const resolved = resolve4(p);
6684
6761
  return allowedBases.some((base) => resolved === base || resolved.startsWith(base + sep3));
6685
6762
  };
6686
6763
  let removedFiles = 0;
@@ -6708,7 +6785,7 @@ async function uninstallPluginById(pluginId, batchMode) {
6708
6785
  const sortedDirs = [...record.directories].filter(isSafePath).sort((a, b) => b.length - a.length);
6709
6786
  for (const dirPath of sortedDirs) {
6710
6787
  try {
6711
- if (resolve3(dirPath) === resolve3(configRoot)) {
6788
+ if (resolve4(dirPath) === resolve4(configRoot)) {
6712
6789
  continue;
6713
6790
  }
6714
6791
  if (existsSync21(dirPath)) {
@@ -6725,7 +6802,7 @@ async function uninstallPluginById(pluginId, batchMode) {
6725
6802
  }
6726
6803
  if (record.tool === "codex") {
6727
6804
  try {
6728
- const agentsRoot = resolve3(getSkillsRoot(record.tool, record.level, record.installPath), "..");
6805
+ const agentsRoot = resolve4(getSkillsRoot(record.tool, record.level, record.installPath), "..");
6729
6806
  if (existsSync21(agentsRoot) && readdirSync11(agentsRoot).length === 0) {
6730
6807
  rmdirSync2(agentsRoot);
6731
6808
  logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename4(agentsRoot)}/`);
@@ -6734,7 +6811,11 @@ async function uninstallPluginById(pluginId, batchMode) {
6734
6811
  } catch {
6735
6812
  }
6736
6813
  }
6737
- deleteRecord(plugin.id);
6814
+ deleteRecord(plugin.id, {
6815
+ tool: record.tool,
6816
+ level: record.level,
6817
+ installPath: record.installPath
6818
+ });
6738
6819
  removeInstalledPlugin(plugin.id);
6739
6820
  const backups = findBackups(configRoot);
6740
6821
  const otherBackups = backups.filter((b) => b.pluginId !== pluginId);