@cannbot-ai/install-helper 1.1.13 → 1.1.14-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/dist/index.js CHANGED
@@ -64,64 +64,20 @@ var init_embedded_plugins = __esm({
64
64
  "direct",
65
65
  "kernel"
66
66
  ],
67
- skills: 21,
68
- agents: 4,
69
- description: "Ascend C \u76F4\u8C03\u5168\u6D41\u7A0B\uFF1A\u73AF\u5883\u2192\u8BBE\u8BA1\u2192\u5F00\u53D1\u2192\u5BA1\u67E5\u2192\u6027\u80FD\u9A8C\u6536",
70
- version: "1.2.5",
67
+ skills: 0,
68
+ agents: 6,
69
+ description: "skill \u9A71\u52A8\u591A\u89D2\u8272\u76F4\u8C03\u7B97\u5B50\u5F00\u53D1\u5DE5\u4F5C\u6D41\uFF1APM \u8C03\u5EA6 architect/developer/qa \u56E2\u961F\uFF0C8 \u9636\u6BB5 7 CP \u5168\u6D41\u7A0B\uFF0C\u652F\u6301\u9759\u9ED8\u6A21\u5F0F\u4E0E\u7B97\u5B50\u4ED3\u7EE7\u627F\u5B9A\u5236",
70
+ version: "2.0.0",
71
71
  configFile: "AGENTS.md",
72
72
  configRootConfigLink: false,
73
- installSkills: [
74
- {
75
- dir: "ops",
76
- skills: [
77
- "ascendc-tiling-design",
78
- "npu-arch",
79
- "ascendc-api-best-practices",
80
- "ascendc-regbase-best-practice",
81
- "ascendc-blaze-best-practice",
82
- "ascendc-blaze-migration",
83
- "ascendc-mc2-best-practice",
84
- "ops-precision-standard",
85
- "ascendc-docs-search",
86
- "ascendc-env-check",
87
- "ascendc-precision-debug",
88
- "ops-profiling",
89
- "ascendc-direct-invoke-template",
90
- "torch-ascendc-op-extension",
91
- "ascendc-runtime-debug",
92
- "ascendc-crash-debug",
93
- "ascendc-code-review"
94
- ]
95
- },
96
- {
97
- dir: "infra",
98
- skills: [
99
- "gitcode-toolkit",
100
- "gitcode-pr-handler",
101
- "gitcode-issue-gen",
102
- "gitcode-issue-handler"
103
- ]
104
- }
105
- ],
73
+ installSkills: [],
106
74
  installAgents: [
107
- "ascendc-kernel-architect",
108
- "ascendc-kernel-design-reviewer",
109
- "ascendc-kernel-developer",
110
- "ascendc-kernel-reviewer"
111
- ],
112
- externalRepos: [
113
- {
114
- url: "https://gitcode.com/cann/asc-devkit.git",
115
- dir: "plugins-official/ops-direct-invoke/asc-devkit",
116
- configRootLink: false
117
- },
118
- {
119
- url: "https://gitcode.com/cann/ops-tensor.git",
120
- dir: "plugins-official/ops-direct-invoke/ops-tensor",
121
- depth: 1,
122
- recursive: true,
123
- configRootLink: false
124
- }
75
+ "architect",
76
+ "developer",
77
+ "developer-code",
78
+ "developer-doc",
79
+ "developer-test",
80
+ "qa"
125
81
  ]
126
82
  },
127
83
  {
@@ -803,6 +759,8 @@ var init_zh_CN = __esm({
803
759
  install_skill_not_found: "Skill \u672A\u627E\u5230: {name} (\u5728 {dir})",
804
760
  install_skill_failed: "Skill \u5B89\u88C5\u5931\u8D25: {name}",
805
761
  install_agent_not_found: "Agent \u672A\u627E\u5230: {name}",
762
+ install_agent_codex_toml_missing: "\u63D2\u4EF6\u672A\u63D0\u4F9B Codex \u9002\u914D\u6587\u4EF6 {path}\uFF0C\u5DF2\u8DF3\u8FC7 agent: {name}",
763
+ error_tool_not_supported: "\u63D2\u4EF6 {plugin} \u7684\u5B89\u88C5\u811A\u672C\u6682\u4E0D\u652F\u6301\u5DE5\u5177 {tool}\uFF08\u4E3A\u907F\u514D\u8BEF\u88C5\u5230\u9ED8\u8BA4\u76EE\u5F55\u5DF2\u4E2D\u6B62\uFF09\uFF0C\u8BF7\u67E5\u770B\u8BE5\u63D2\u4EF6 quickstart.md \u786E\u8BA4\u652F\u6301\u7684\u5DE5\u5177\u5217\u8868",
806
764
  install_agent_failed: "Agent \u5B89\u88C5\u5931\u8D25: {name}",
807
765
  install_no_skill_selected: "\u672A\u9009\u62E9\u4EFB\u4F55 Skill",
808
766
  install_to: "\u5B89\u88C5\u5230",
@@ -1026,6 +984,8 @@ var init_en_US = __esm({
1026
984
  install_skill_not_found: "Skill not found: {name} in {dir}",
1027
985
  install_skill_failed: "Failed to install skill: {name}",
1028
986
  install_agent_not_found: "Agent not found: {name}",
987
+ install_agent_codex_toml_missing: "Codex adapter file {path} not found in plugin, agent skipped: {name}",
988
+ error_tool_not_supported: "Plugin {plugin} does not support tool {tool} yet (aborted to avoid mis-installing into default directories); see the plugin quickstart.md for supported tools",
1029
989
  install_agent_failed: "Failed to install agent: {name}",
1030
990
  install_no_skill_selected: "No Skill selected",
1031
991
  install_to: "Install to",
@@ -1196,6 +1156,8 @@ function getConfigRoot(tool, level, base) {
1196
1156
  }
1197
1157
  case "cursor":
1198
1158
  return join3(home, ".cursor");
1159
+ case "codex":
1160
+ return join3(home, ".codex");
1199
1161
  case "copilot":
1200
1162
  return join3(home, ".copilot");
1201
1163
  case "codearts":
@@ -1225,6 +1187,8 @@ function getConfigRoot(tool, level, base) {
1225
1187
  }
1226
1188
  case "cursor":
1227
1189
  return join3(baseDir, ".cursor");
1190
+ case "codex":
1191
+ return join3(baseDir, ".codex");
1228
1192
  case "copilot":
1229
1193
  return join3(baseDir, ".github");
1230
1194
  case "codearts":
@@ -1238,12 +1202,18 @@ function getConfigRoot(tool, level, base) {
1238
1202
  function getConfigFileName(tool) {
1239
1203
  return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1240
1204
  }
1205
+ function getSkillsRoot(tool, level, base) {
1206
+ if (tool === "codex") {
1207
+ if (level === "global") {
1208
+ return join3(homedir(), ".agents", "skills");
1209
+ }
1210
+ return join3(base || process.cwd(), ".agents", "skills");
1211
+ }
1212
+ return join3(getConfigRoot(tool, level, base), "skills");
1213
+ }
1241
1214
  function getAgentsFileName(tool) {
1242
1215
  return getConfigFileName(tool);
1243
1216
  }
1244
- function getSkillsDir(configRoot) {
1245
- return join3(configRoot, "skills");
1246
- }
1247
1217
  function getAgentsDir(configRoot) {
1248
1218
  return join3(configRoot, "agents");
1249
1219
  }
@@ -1261,7 +1231,7 @@ var init_paths = __esm({
1261
1231
  "src/utils/paths.ts"() {
1262
1232
  "use strict";
1263
1233
  init_i18n();
1264
- VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "copilot", "codearts"];
1234
+ VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "codex", "copilot", "codearts"];
1265
1235
  VALID_LEVELS = ["project", "global"];
1266
1236
  }
1267
1237
  });
@@ -1333,6 +1303,19 @@ async function detectCursor() {
1333
1303
  }
1334
1304
  return void 0;
1335
1305
  }
1306
+ async function detectCodex() {
1307
+ const cmdPath = await getCommandPath("codex");
1308
+ if (cmdPath) {
1309
+ const version = await getCommandVersion("codex");
1310
+ return { name: "codex", version, path: cmdPath };
1311
+ }
1312
+ const home = homedir2();
1313
+ const configDir = join4(home, ".codex");
1314
+ if (existsSync4(configDir)) {
1315
+ return { name: "codex", path: configDir };
1316
+ }
1317
+ return void 0;
1318
+ }
1336
1319
  async function detectCopilot() {
1337
1320
  const path = await getCommandPath("gh");
1338
1321
  if (!path) return void 0;
@@ -1357,6 +1340,7 @@ async function detectTools() {
1357
1340
  detectClaude,
1358
1341
  detectTrae,
1359
1342
  detectCursor,
1343
+ detectCodex,
1360
1344
  detectCopilot,
1361
1345
  detectCodeArts
1362
1346
  ];
@@ -1375,6 +1359,7 @@ function getToolDisplayName(tool) {
1375
1359
  claude: "Claude Code",
1376
1360
  trae: "Trae",
1377
1361
  cursor: "Cursor",
1362
+ codex: "Codex",
1378
1363
  copilot: "GitHub Copilot",
1379
1364
  codearts: "CodeArts"
1380
1365
  };
@@ -1462,7 +1447,7 @@ function scanInstalled() {
1462
1447
  return installed;
1463
1448
  }
1464
1449
  function verifyPluginFilesExist(configRoot, manifest, tool, level) {
1465
- const skillsDir = join5(configRoot, "skills");
1450
+ const skillsDir = getSkillsRoot(tool, level);
1466
1451
  const agentsDir = join5(configRoot, "agents");
1467
1452
  let hasAnyComponent = false;
1468
1453
  if (manifest.installed_skills && manifest.installed_skills.length > 0) {
@@ -2323,7 +2308,7 @@ var STATIC_SKILL_CATEGORIES = [
2323
2308
  { id: "ascendc-blaze-migration", description: "AscendC Matmul \u5BB6\u65CF\u7B49\u4EF7\u8FC1\u79FB\u5230 Blaze", source: "ops" },
2324
2309
  { id: "ascendc-simt-best-practices", description: "SIMT \u6700\u4F73\u5B9E\u8DF5\u4E0E API \u5BFC\u822A", source: "ops" },
2325
2310
  { id: "ascendc-simt-tiling-design", description: "SIMT \u7B97\u5B50\u5207\u5206\u8BBE\u8BA1", source: "ops" },
2326
- { id: "torch-ascendc-op-extension", description: "Ascend C \u5BF9\u63A5 PyTorch", source: "ops" },
2311
+ { id: "torch-ascendc-op-extension", description: "\u7B97\u5B50\u5BF9\u63A5 PyTorch\uFF08kernel \u76F4\u8C03 / aclnn \u6CE8\u518C\u53CC\u8DEF\u7EBF\uFF09", source: "ops" },
2327
2312
  { id: "catlass-op-design", description: "Catlass \u7B97\u5B50\u8BBE\u8BA1", source: "ops" },
2328
2313
  { id: "catlass-op-develop", description: "Catlass \u7B97\u5B50\u5F00\u53D1", source: "ops" },
2329
2314
  { id: "catlass-op-perf-tune", description: "Catlass \u6027\u80FD\u8C03\u4F18", source: "ops" },
@@ -2772,7 +2757,7 @@ function createRepositoryManager(customPath) {
2772
2757
  init_registry();
2773
2758
  init_manifest();
2774
2759
  init_paths();
2775
- import { existsSync as existsSync14 } from "fs";
2760
+ import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
2776
2761
  import { join as join13, basename as basename2 } from "path";
2777
2762
  import { execa as execa4, execaSync } from "execa";
2778
2763
 
@@ -2821,7 +2806,7 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
2821
2806
  const files = [];
2822
2807
  const directories = [];
2823
2808
  if (manifest) {
2824
- const skillsDir = join10(configRoot, "skills");
2809
+ const skillsDir = getSkillsRoot(tool, level, installPath);
2825
2810
  if (existsSync11(skillsDir)) {
2826
2811
  directories.push(skillsDir);
2827
2812
  for (const skillName of manifest.installed_skills || []) {
@@ -2970,8 +2955,7 @@ function removeSkillsFromRecord(skillIds, tool, level, installPath) {
2970
2955
  function getInstalledSkills(tool, level, installPath, allowFsScan = true) {
2971
2956
  const record = readSkillRecord();
2972
2957
  const recordedSkills = record[tool]?.[level]?.[installPath]?.skills || [];
2973
- const configRoot = getConfigRoot(tool, level);
2974
- const skillsDir = join10(configRoot, "skills");
2958
+ const skillsDir = getSkillsRoot(tool, level);
2975
2959
  const fromRecord = recordedSkills.filter((skillId) => {
2976
2960
  const skillPath = join10(skillsDir, skillId);
2977
2961
  return existsSync11(skillPath) || isSymlink(skillPath);
@@ -3002,8 +2986,7 @@ function getLastBatchSkills(tool, level, installPath) {
3002
2986
  return null;
3003
2987
  }
3004
2988
  const lastBatch = entry.batches[entry.batches.length - 1];
3005
- const configRoot = level === "project" ? getConfigRoot(tool, level, installPath) : getConfigRoot(tool, level);
3006
- const skillsDir = join10(configRoot, "skills");
2989
+ const skillsDir = getSkillsRoot(tool, level, installPath);
3007
2990
  return lastBatch.skills.filter((skillId) => {
3008
2991
  const skillPath = join10(skillsDir, skillId);
3009
2992
  return existsSync11(skillPath) || isSymlink(skillPath);
@@ -3186,7 +3169,7 @@ init_paths();
3186
3169
  init_fs_helpers();
3187
3170
  init_logger();
3188
3171
  init_i18n();
3189
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, symlinkSync, realpathSync, readlinkSync, copyFileSync as copyFileSync2, cpSync, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "fs";
3172
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, symlinkSync, realpathSync, readlinkSync, copyFileSync as copyFileSync2, cpSync, writeFileSync as writeFileSync2, rmSync as rmSync3, readFileSync as readFileSync8 } from "fs";
3190
3173
  import { join as join12, basename } from "path";
3191
3174
  import { execa as execa3 } from "execa";
3192
3175
  function installLink(source, target) {
@@ -3375,7 +3358,7 @@ async function installViaManifest(plugin, repoPath, tool, level, installPath) {
3375
3358
  const configRoot = getConfigRoot(tool, level, installPath);
3376
3359
  const pluginDir = join12(repoPath, plugin.dir);
3377
3360
  try {
3378
- const skillsDir = join12(configRoot, "skills");
3361
+ const skillsDir = getSkillsRoot(tool, level, cwd);
3379
3362
  const agentsDir = join12(configRoot, "agents");
3380
3363
  mkdirSync5(skillsDir, { recursive: true });
3381
3364
  mkdirSync5(agentsDir, { recursive: true });
@@ -3405,6 +3388,28 @@ async function installViaManifest(plugin, repoPath, tool, level, installPath) {
3405
3388
  }
3406
3389
  }
3407
3390
  for (const agentName of plugin.installAgents || []) {
3391
+ if (tool === "codex") {
3392
+ const baseName = agentName.replace(/\.md$/, "");
3393
+ const tomlSource = join12(pluginDir, "agents", "codex", `${baseName}.toml`);
3394
+ if (!existsSync13(tomlSource)) {
3395
+ logger.warn(t("install_agent_codex_toml_missing").replace("{name}", baseName).replace("{path}", tomlSource));
3396
+ continue;
3397
+ }
3398
+ const canonicalMd = join12(pluginDir, "agents", `${baseName}.md`);
3399
+ const canonicalPath = existsSync13(canonicalMd) ? realpathSync(canonicalMd) : canonicalMd;
3400
+ const targetPath2 = join12(agentsDir, `${baseName}.toml`);
3401
+ try {
3402
+ const content = readFileSync8(tomlSource, "utf-8").split("__CANNBOT_AGENT_SOURCE__").join(canonicalPath);
3403
+ if (existsSync13(targetPath2) || isSymlink(targetPath2)) {
3404
+ removePath(targetPath2);
3405
+ }
3406
+ writeFileSync2(targetPath2, content, "utf-8");
3407
+ installedAgents.push(`${baseName}.toml`);
3408
+ } catch {
3409
+ logger.warn(t("install_agent_failed").replace("{name}", `${baseName}.toml`));
3410
+ }
3411
+ continue;
3412
+ }
3408
3413
  const agentFile = agentName.endsWith(".md") ? agentName : `${agentName}.md`;
3409
3414
  const agentPath = join12(pluginDir, "agents", agentFile);
3410
3415
  if (!existsSync13(agentPath)) {
@@ -3464,6 +3469,14 @@ function findShell() {
3464
3469
  }
3465
3470
  return null;
3466
3471
  }
3472
+ function scriptSupportsTool(scriptPath, tool) {
3473
+ try {
3474
+ const scriptContent = readFileSync9(scriptPath, "utf-8");
3475
+ return new RegExp(`\\b${tool}\\b`).test(scriptContent);
3476
+ } catch {
3477
+ return true;
3478
+ }
3479
+ }
3467
3480
  async function installPlugin(opts) {
3468
3481
  const plugin = getPluginById(opts.pluginId);
3469
3482
  if (!plugin) {
@@ -3587,6 +3600,16 @@ async function installPlugin(opts) {
3587
3600
  warnings: []
3588
3601
  };
3589
3602
  }
3603
+ if (!scriptSupportsTool(scriptPath, opts.tool)) {
3604
+ return {
3605
+ success: false,
3606
+ pluginId: opts.pluginId,
3607
+ skillsCount: 0,
3608
+ agentsCount: 0,
3609
+ errors: [t("error_tool_not_supported").replace("{plugin}", plugin.displayName).replace("{tool}", opts.tool)],
3610
+ warnings: []
3611
+ };
3612
+ }
3590
3613
  const args = [opts.level, opts.tool];
3591
3614
  if (opts.installPath) {
3592
3615
  args.push(opts.installPath);
@@ -3675,7 +3698,7 @@ init_constants();
3675
3698
  init_logger();
3676
3699
  init_i18n();
3677
3700
  import { existsSync as existsSync15, mkdirSync as mkdirSync6, symlinkSync as symlinkSync2, readdirSync as readdirSync6, rmSync as rmSync4, realpathSync as realpathSync2, readlinkSync as readlinkSync2, cpSync as cpSync2 } from "fs";
3678
- import { join as join14, dirname as dirname5, isAbsolute } from "path";
3701
+ import { join as join14, dirname as dirname5, basename as basename3, isAbsolute } from "path";
3679
3702
  import { select as select3, checkbox, Separator as Separator2 } from "@inquirer/prompts";
3680
3703
  import chalk5 from "chalk";
3681
3704
  import Table from "cli-table3";
@@ -3683,7 +3706,7 @@ init_theme();
3683
3706
  import { confirm } from "@inquirer/prompts";
3684
3707
  async function installSkills(skillIds, tool, level, repoPath) {
3685
3708
  const configRoot = getConfigRoot(tool, level);
3686
- const skillsDir = join14(configRoot, "skills");
3709
+ const skillsDir = getSkillsRoot(tool, level);
3687
3710
  const installPath = level === "project" ? process.cwd() : configRoot;
3688
3711
  if (!existsSync15(skillsDir)) {
3689
3712
  mkdirSync6(skillsDir, { recursive: true });
@@ -3749,7 +3772,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
3749
3772
  }
3750
3773
  async function uninstallSkills(skillIds, tool, level) {
3751
3774
  const configRoot = getConfigRoot(tool, level);
3752
- const skillsDir = join14(configRoot, "skills");
3775
+ const skillsDir = getSkillsRoot(tool, level);
3753
3776
  const installPath = level === "project" ? process.cwd() : configRoot;
3754
3777
  const results = [];
3755
3778
  const removedIds = [];
@@ -3778,6 +3801,16 @@ async function uninstallSkills(skillIds, tool, level) {
3778
3801
  if (entries.length === 0) {
3779
3802
  rmSync4(skillsDir, { recursive: true });
3780
3803
  logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
3804
+ if (tool === "codex") {
3805
+ const agentsRoot = dirname5(skillsDir);
3806
+ try {
3807
+ if (existsSync15(agentsRoot) && readdirSync6(agentsRoot).length === 0) {
3808
+ rmSync4(agentsRoot, { recursive: true });
3809
+ logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename3(agentsRoot)}/`);
3810
+ }
3811
+ } catch {
3812
+ }
3813
+ }
3781
3814
  }
3782
3815
  } catch {
3783
3816
  }
@@ -4287,13 +4320,13 @@ init_config();
4287
4320
  init_paths();
4288
4321
  init_theme();
4289
4322
  init_constants();
4290
- import { existsSync as existsSync16, readFileSync as readFileSync8 } from "fs";
4323
+ import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
4291
4324
  import { join as join15 } from "path";
4292
4325
  async function initCommand() {
4293
4326
  const cwd = process.cwd();
4294
4327
  if (existsSync16(join15(cwd, "package.json")) && (() => {
4295
4328
  try {
4296
- const pkg = JSON.parse(readFileSync8(join15(cwd, "package.json"), "utf-8"));
4329
+ const pkg = JSON.parse(readFileSync10(join15(cwd, "package.json"), "utf-8"));
4297
4330
  return pkg.name === "@cannbot-ai/install-helper";
4298
4331
  } catch {
4299
4332
  return false;
@@ -4502,11 +4535,10 @@ async function skillInstallFlow() {
4502
4535
  failCount++;
4503
4536
  }
4504
4537
  }
4505
- const configRoot = getConfigRoot(tool, level);
4506
4538
  logger.blank();
4507
4539
  logger.success(`${t("skill_install_done")}: ${chalk7.green(t("result_success_format").replace("{count}", String(successCount)))}, ${failCount > 0 ? chalk7.red(t("result_failed_format").replace("{count}", String(failCount))) : chalk7.dim(t("result_failed_format").replace("{count}", String(failCount)))}`);
4508
4540
  logger.blank();
4509
- logger.info(`${t("install_to")}: ${chalk7.cyan(join15(configRoot, "skills"))}`);
4541
+ logger.info(`${t("install_to")}: ${chalk7.cyan(getSkillsRoot(tool, level))}`);
4510
4542
  logger.info(`${t("start_to_use").replace("{tool}", chalk7.green(tool))}`);
4511
4543
  logger.blank();
4512
4544
  return "done";
@@ -4590,8 +4622,8 @@ async function doctorCommand(options = {}) {
4590
4622
  const configRoot = getConfigRoot(primaryTool, "project");
4591
4623
  configRootsToCheck.push({ configRoot, tool: primaryTool, level: "project" });
4592
4624
  }
4593
- for (const { configRoot } of configRootsToCheck) {
4594
- const skillsDir = getSkillsDir(configRoot);
4625
+ for (const { configRoot, tool, level } of configRootsToCheck) {
4626
+ const skillsDir = getSkillsRoot(tool, level);
4595
4627
  const agentsDir = getAgentsDir(configRoot);
4596
4628
  if (existsSync17(skillsDir)) {
4597
4629
  const brokenLinks = checkBrokenLinks(skillsDir);
@@ -4742,7 +4774,6 @@ init_logger();
4742
4774
  init_i18n();
4743
4775
  init_config();
4744
4776
  init_paths();
4745
- import { join as join17 } from "path";
4746
4777
  import { confirm as confirm2 } from "@inquirer/prompts";
4747
4778
  import chalk10 from "chalk";
4748
4779
  async function installCommand(names, options) {
@@ -4810,11 +4841,10 @@ async function installCommand(names, options) {
4810
4841
  failCount++;
4811
4842
  }
4812
4843
  }
4813
- const configRoot = getConfigRoot(tool2, level2);
4814
4844
  logger.blank();
4815
4845
  logger.success(`${t("skill_install_done")}: ${chalk10.green(t("result_success_format").replace("{count}", String(successCount)))}, ${failCount > 0 ? chalk10.red(t("result_failed_format").replace("{count}", String(failCount))) : chalk10.dim(t("result_failed_format").replace("{count}", String(failCount)))}`);
4816
4846
  logger.blank();
4817
- logger.info(`${t("install_to")}: ${chalk10.cyan(join17(configRoot, "skills"))}`);
4847
+ logger.info(`${t("install_to")}: ${chalk10.cyan(getSkillsRoot(tool2, level2))}`);
4818
4848
  logger.info(`${t("start_to_use").replace("{tool}", chalk10.green(tool2))}`);
4819
4849
  logger.blank();
4820
4850
  return;
@@ -4891,11 +4921,10 @@ async function installCommand(names, options) {
4891
4921
  failCount++;
4892
4922
  }
4893
4923
  }
4894
- const configRoot = getConfigRoot(tool2, level2);
4895
4924
  logger.blank();
4896
4925
  logger.success(`${t("skill_install_done")}: ${chalk10.green(t("result_success_format").replace("{count}", String(successCount)))}, ${failCount > 0 ? chalk10.red(t("result_failed_format").replace("{count}", String(failCount))) : chalk10.dim(t("result_failed_format").replace("{count}", String(failCount)))}`);
4897
4926
  logger.blank();
4898
- logger.info(`${t("install_to")}: ${chalk10.cyan(join17(configRoot, "skills"))}`);
4927
+ logger.info(`${t("install_to")}: ${chalk10.cyan(getSkillsRoot(tool2, level2))}`);
4899
4928
  logger.info(`${t("start_to_use").replace("{tool}", chalk10.green(tool2))}`);
4900
4929
  logger.blank();
4901
4930
  return;
@@ -5037,7 +5066,7 @@ async function installCommand(names, options) {
5037
5066
  logger.blank();
5038
5067
  logger.success(`${t("skill_install_done")}: ${chalk10.green(t("result_success_format").replace("{count}", String(successCount)))}, ${failCount > 0 ? chalk10.red(t("result_failed_format").replace("{count}", String(failCount))) : chalk10.dim(t("result_failed_format").replace("{count}", String(failCount)))}`);
5039
5068
  logger.blank();
5040
- logger.info(`${t("install_to")}: ${chalk10.cyan(join17(getConfigRoot(tool, level), "skills"))}`);
5069
+ logger.info(`${t("install_to")}: ${chalk10.cyan(getSkillsRoot(tool, level))}`);
5041
5070
  logger.info(`${t("start_to_use").replace("{tool}", chalk10.green(tool))}`);
5042
5071
  logger.blank();
5043
5072
  }
@@ -5073,8 +5102,8 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
5073
5102
 
5074
5103
  // src/commands/uninstall.ts
5075
5104
  init_registry();
5076
- import { existsSync as existsSync18, unlinkSync as unlinkSync6, rmdirSync, readdirSync as readdirSync8, readFileSync as readFileSync9 } from "fs";
5077
- import { resolve, basename as basename3, sep as sep2, join as join18 } from "path";
5105
+ import { existsSync as existsSync18, unlinkSync as unlinkSync6, rmdirSync, readdirSync as readdirSync8, readFileSync as readFileSync11 } from "fs";
5106
+ import { resolve, basename as basename4, sep as sep2, join as join17 } from "path";
5078
5107
  import chalk11 from "chalk";
5079
5108
  import { select as select5, checkbox as checkbox2, Separator as Separator4, confirm as confirm3 } from "@inquirer/prompts";
5080
5109
  init_config();
@@ -5115,6 +5144,10 @@ async function uninstallCommand(names, options) {
5115
5144
  skills.push(skill.id);
5116
5145
  continue;
5117
5146
  }
5147
+ if (readRecord(name)) {
5148
+ plugins.push(name);
5149
+ continue;
5150
+ }
5118
5151
  logger.error(`${t("uninstall_not_found")}: ${name}`);
5119
5152
  }
5120
5153
  await uninstallPlugins(plugins, options.yes || false);
@@ -5197,7 +5230,7 @@ async function uninstallInteractive(defaultTool, defaultLevel, userSpecifiedTool
5197
5230
  const allInstalledPlugins = scanInstalled();
5198
5231
  const toolsWithPlugins = new Set(allInstalledPlugins.map((p) => `${p.tool}:${p.level}`));
5199
5232
  const toolsWithSkills = /* @__PURE__ */ new Set();
5200
- for (const toolName of ["opencode", "claude", "trae", "cursor", "copilot", "codearts"]) {
5233
+ for (const toolName of VALID_TOOLS) {
5201
5234
  for (const lvl of ["project", "global"]) {
5202
5235
  const ip = lvl === "project" ? process.cwd() : getConfigRoot(toolName, lvl);
5203
5236
  const skills = getInstalledSkills(toolName, lvl, ip);
@@ -5353,18 +5386,33 @@ async function uninstallPlugins(pluginIds, batchMode) {
5353
5386
  }
5354
5387
  }
5355
5388
  async function uninstallPluginById(pluginId, batchMode) {
5356
- const plugin = findPlugin(pluginId);
5389
+ let plugin = findPlugin(pluginId);
5390
+ if (!plugin) {
5391
+ const record2 = readRecord(pluginId);
5392
+ if (record2) {
5393
+ plugin = {
5394
+ id: pluginId,
5395
+ dir: "",
5396
+ displayName: record2.displayName,
5397
+ script: "init.sh",
5398
+ aliases: [],
5399
+ skills: 0,
5400
+ agents: 0,
5401
+ description: ""
5402
+ };
5403
+ }
5404
+ }
5357
5405
  if (!plugin) return;
5358
5406
  let record = readRecord(plugin.id);
5359
5407
  if (!record) {
5360
5408
  for (const toolName of VALID_TOOLS) {
5361
5409
  for (const lvl of ["project", "global"]) {
5362
5410
  const configRoot2 = getConfigRoot(toolName, lvl);
5363
- const manifestPath = join18(configRoot2, `${pluginId}-manifest.json`);
5411
+ const manifestPath = join17(configRoot2, `${pluginId}-manifest.json`);
5364
5412
  if (!existsSync18(manifestPath)) continue;
5365
5413
  let manifest = null;
5366
5414
  try {
5367
- manifest = JSON.parse(readFileSync9(manifestPath, "utf-8"));
5415
+ manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
5368
5416
  } catch {
5369
5417
  continue;
5370
5418
  }
@@ -5377,7 +5425,7 @@ async function uninstallPluginById(pluginId, batchMode) {
5377
5425
  installPath,
5378
5426
  configRoot2,
5379
5427
  manifest,
5380
- plugin.externalRepos?.map((r) => basename3(r.dir)),
5428
+ plugin.externalRepos?.map((r) => basename4(r.dir)),
5381
5429
  plugin.configRootConfigLink
5382
5430
  );
5383
5431
  break;
@@ -5393,6 +5441,9 @@ async function uninstallPluginById(pluginId, batchMode) {
5393
5441
  logger.info(`${t("uninstall_in_progress")} ${plugin.displayName}...`);
5394
5442
  const configRoot = getConfigRoot(record.tool, record.level);
5395
5443
  const allowedBases = [resolve(configRoot), resolve(record.installPath)];
5444
+ if (record.tool === "codex") {
5445
+ allowedBases.push(resolve(getSkillsRoot(record.tool, record.level, record.installPath)));
5446
+ }
5396
5447
  const isSafePath = (p) => {
5397
5448
  const resolved = resolve(p);
5398
5449
  return allowedBases.some((base) => resolved === base || resolved.startsWith(base + sep2));
@@ -5400,8 +5451,8 @@ async function uninstallPluginById(pluginId, batchMode) {
5400
5451
  let removedFiles = 0;
5401
5452
  let removedDirs = 0;
5402
5453
  const configFileName = record.tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
5403
- const configRootConfigPath = join18(configRoot, configFileName);
5404
- const installPathConfigPath = join18(record.installPath, configFileName);
5454
+ const configRootConfigPath = join17(configRoot, configFileName);
5455
+ const installPathConfigPath = join17(record.installPath, configFileName);
5405
5456
  const extraFiles = [];
5406
5457
  if (record.level === "project" && configRootConfigPath !== installPathConfigPath && !record.files.includes(configRootConfigPath) && (existsSync18(configRootConfigPath) || isSymlink(configRootConfigPath))) {
5407
5458
  extraFiles.push(configRootConfigPath);
@@ -5412,7 +5463,7 @@ async function uninstallPluginById(pluginId, batchMode) {
5412
5463
  try {
5413
5464
  if (existsSync18(filePath) || isSymlink(filePath)) {
5414
5465
  unlinkSync6(filePath);
5415
- const name = basename3(filePath);
5466
+ const name = basename4(filePath);
5416
5467
  logger.step(` ${t("uninstall_remove_label")}: ${name}`);
5417
5468
  removedFiles++;
5418
5469
  }
@@ -5429,7 +5480,7 @@ async function uninstallPluginById(pluginId, batchMode) {
5429
5480
  const entries = readdirSync8(dirPath);
5430
5481
  if (entries.length === 0) {
5431
5482
  rmdirSync(dirPath);
5432
- const name = basename3(dirPath);
5483
+ const name = basename4(dirPath);
5433
5484
  logger.step(` ${t("uninstall_clean_empty_dir")}: ${name}/`);
5434
5485
  removedDirs++;
5435
5486
  }
@@ -5437,6 +5488,17 @@ async function uninstallPluginById(pluginId, batchMode) {
5437
5488
  } catch {
5438
5489
  }
5439
5490
  }
5491
+ if (record.tool === "codex") {
5492
+ try {
5493
+ const agentsRoot = resolve(getSkillsRoot(record.tool, record.level, record.installPath), "..");
5494
+ if (existsSync18(agentsRoot) && readdirSync8(agentsRoot).length === 0) {
5495
+ rmdirSync(agentsRoot);
5496
+ logger.step(` ${t("uninstall_clean_empty_dir")}: ${basename4(agentsRoot)}/`);
5497
+ removedDirs++;
5498
+ }
5499
+ } catch {
5500
+ }
5501
+ }
5440
5502
  deleteRecord(plugin.id);
5441
5503
  removeInstalledPlugin(plugin.id);
5442
5504
  const backups = findBackups(configRoot);
@@ -5588,7 +5650,7 @@ async function updateCommand(pluginNames, options) {
5588
5650
  init_registry();
5589
5651
  import chalk13 from "chalk";
5590
5652
  import { existsSync as existsSync19, readdirSync as readdirSync9 } from "fs";
5591
- import { join as join19 } from "path";
5653
+ import { join as join18 } from "path";
5592
5654
  init_manifest();
5593
5655
  init_i18n();
5594
5656
  async function infoCommand(pluginName) {
@@ -5615,11 +5677,11 @@ async function infoCommand(pluginName) {
5615
5677
  try {
5616
5678
  const repoManager = createRepositoryManager();
5617
5679
  const repoPath = await repoManager.ensureRepo();
5618
- const quickstartPath = join19(repoPath, plugin.dir, "quickstart.md");
5680
+ const quickstartPath = join18(repoPath, plugin.dir, "quickstart.md");
5619
5681
  if (existsSync19(quickstartPath)) {
5620
5682
  console.log(` ${chalk13.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
5621
5683
  }
5622
- const agentsDir = join19(repoPath, plugin.dir, "agents");
5684
+ const agentsDir = join18(repoPath, plugin.dir, "agents");
5623
5685
  if (existsSync19(agentsDir)) {
5624
5686
  const agentFiles = readdirSync9(agentsDir).filter((f) => f.endsWith(".md"));
5625
5687
  if (agentFiles.length > 0) {
@@ -5676,9 +5738,9 @@ async function langCommand(action, value) {
5676
5738
  // src/cli.ts
5677
5739
  init_config();
5678
5740
  init_i18n();
5679
- import { readFileSync as readFileSync10, existsSync as existsSync20 } from "fs";
5741
+ import { readFileSync as readFileSync12, existsSync as existsSync20 } from "fs";
5680
5742
  import { fileURLToPath as fileURLToPath4 } from "url";
5681
- import { dirname as dirname6, join as join20 } from "path";
5743
+ import { dirname as dirname6, join as join19 } from "path";
5682
5744
  function readVersion() {
5683
5745
  try {
5684
5746
  if (typeof INSTALL_HELPER_VERSION !== "undefined" && INSTALL_HELPER_VERSION) {
@@ -5690,13 +5752,13 @@ function readVersion() {
5690
5752
  const __filename4 = fileURLToPath4(import.meta.url);
5691
5753
  const __dirname4 = dirname6(__filename4);
5692
5754
  const candidates = [
5693
- join20(__dirname4, "..", "package.json"),
5694
- join20(__dirname4, "package.json"),
5695
- join20(process.cwd(), "package.json")
5755
+ join19(__dirname4, "..", "package.json"),
5756
+ join19(__dirname4, "package.json"),
5757
+ join19(process.cwd(), "package.json")
5696
5758
  ];
5697
5759
  for (const pkgPath of candidates) {
5698
5760
  if (existsSync20(pkgPath)) {
5699
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
5761
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5700
5762
  if (pkg.version && (pkg.name === "@cannbot-ai/install-helper" || pkg.name?.startsWith("@cannbot-ai/install-helper-"))) {
5701
5763
  return pkg.version;
5702
5764
  }
@@ -5726,13 +5788,13 @@ function createCLI() {
5726
5788
  program2.command("status").description("Show installed plugins").action(async () => {
5727
5789
  await statusCommand();
5728
5790
  });
5729
- program2.command("install [names...]").description("Install plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Install ALL available skills").option("--list", "List all available skills by category").action(async (names, options) => {
5791
+ program2.command("install [names...]").description("Install plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, codex, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Install ALL available skills").option("--list", "List all available skills by category").action(async (names, options) => {
5730
5792
  await installCommand(names, options);
5731
5793
  });
5732
- program2.command("uninstall [names...]").description("Uninstall plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Uninstall ALL installed skills and plugins").option("--recent", "Uninstall the most recently installed skill batch").action(async (names, options) => {
5794
+ program2.command("uninstall [names...]").description("Uninstall plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, codex, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Uninstall ALL installed skills and plugins").option("--recent", "Uninstall the most recently installed skill batch").action(async (names, options) => {
5733
5795
  await uninstallCommand(names, options);
5734
5796
  });
5735
- program2.command("update [plugins...]").description("Update installed plugins (git pull + reinstall)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)").option("-y, --yes", "Skip confirmation prompts").action(async (plugins, options) => {
5797
+ program2.command("update [plugins...]").description("Update installed plugins (git pull + reinstall)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, codex, copilot, codearts)").option("-l, --level <level>", "Install level (project, global)").option("-y, --yes", "Skip confirmation prompts").action(async (plugins, options) => {
5736
5798
  await updateCommand(plugins, options);
5737
5799
  });
5738
5800
  program2.command("info <plugin>").description("Show plugin details").action(async (plugin) => {