@cannbot-ai/install-helper 1.2.2-beta.1 → 1.2.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -123,6 +123,8 @@ install-helper uninstall ops-direct-invoke # 卸载
123
123
  - 需要 Node.js 运行环境
124
124
  - 离线/调试:`CANNBOT_INSTALLER_PATH` 指定安装器包路径,`CANNBOT_INSTALLER_CHANNEL` 覆盖通道
125
125
 
126
+ 超出上述委托矩阵(qoder / cursor / copilot / codearts 工具或 global 级别)时,未显式指定 `--source cannbot` 的安装会自动回退到本仓冻结副本并提示原因;显式指定 `--source cannbot` 仍按报错处理,仅存于 cannbot 仓、无本地副本可回退的插件(如 triton-op-generator)则给出结构化错误。
127
+
126
128
  ### 更新
127
129
 
128
130
  ```bash
@@ -212,7 +214,6 @@ install-helper lang set en_US # 切换为英文
212
214
  | 5 | NPU 推理优化 | model-infer-optimize | model-infer, infer, inference, sota, sota-approach, model-infer-sota |
213
215
  | 6 | PyPTO 算子开发 | pypto-op-orchestrator | pypto, pytorch |
214
216
  | 7 | TileLang 算子开发 | tilelang-op-orchestrator | tilelang |
215
- | 8 | Triton 算子开发 | triton-op-generator | triton |
216
217
  | 9 | torch.compile 图模式 | torch-compile | torch, compile, graph |
217
218
  | 10 | 代码检视 | ops-code-reviewer | code-review, reviewer, review |
218
219
 
package/dist/index.js CHANGED
@@ -154,7 +154,7 @@ var init_zh_CN = __esm({
154
154
  info_aliases: "\u522B\u540D",
155
155
  uninstall_not_found: "\u672A\u627E\u5230",
156
156
  uninstall_no_record: "\u672A\u627E\u5230\u5B89\u88C5\u8BB0\u5F55\uFF0C\u53EF\u80FD\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
157
- uninstall_no_record_hint: "\u5982\u9700\u5F3A\u5236\u6E05\u7406\uFF0C\u8BF7\u624B\u52A8\u5220\u9664\u5BF9\u5E94\u5DE5\u5177\u914D\u7F6E\u76EE\u5F55\u4E2D\u7684\u76F8\u5173\u6587\u4EF6\uFF08\u5982 .opencode/\u3001.claude/\u3001.trae/\u3001.cursor/\u3001.codex/ \u4E0E .agents/\u3001.github/\u3001.codeartsdoer/\uFF09",
157
+ uninstall_no_record_hint: "\u5982\u9700\u5F3A\u5236\u6E05\u7406\uFF0C\u8BF7\u624B\u52A8\u5220\u9664\u5BF9\u5E94\u5DE5\u5177\u914D\u7F6E\u76EE\u5F55\u4E2D\u7684\u76F8\u5173\u6587\u4EF6\uFF08\u5982 .opencode/\u3001.claude/\u3001.trae/\u3001.cursor/\u3001.codex/ \u4E0E .agents/\u3001.github/\u3001.codeartsdoer/\u3001.qoder/ \u4E0E .qoder-cn/\u3001.lingma/\uFF09",
158
158
  uninstall_in_progress: "\u6B63\u5728\u5378\u8F7D",
159
159
  uninstall_summary_format: "{name}\uFF08\u79FB\u9664 {files} \u4E2A\u6587\u4EF6\uFF0C{dirs} \u4E2A\u76EE\u5F55\uFF09",
160
160
  uninstall_files_gone: "\u7684\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728\uFF0C\u5DF2\u6E05\u7406\u5B89\u88C5\u8BB0\u5F55",
@@ -292,6 +292,8 @@ var init_zh_CN = __esm({
292
292
  cannbot_registry_missing: "\u5B89\u88C5\u540E\u672A\u5728 cannbot-plugin.json \u4E2D\u627E\u5230\u6CE8\u518C\u8BB0\u5F55",
293
293
  cannbot_delegate_failed: "cannbot \u5B89\u88C5\u5668\u6267\u884C\u5931\u8D25\uFF08\u9000\u51FA\u7801 {code}\uFF09\uFF0C\u8F93\u51FA\u89C1\u4E0A\u65B9\u65E5\u5FD7",
294
294
  cannbot_bundled_fallback: "\u4E0A\u6E38\u5B89\u88C5\u5668\u6682\u4E0D\u8BC6\u522B\u65B0\u7248 plugins-official \u76EE\u5F55\uFF08\u7B49\u5F85\u5176\u53D1\u7248\u4FEE\u590D\uFF09\uFF0C\u5DF2\u81EA\u52A8\u56DE\u9000\u4E3A\u5B89\u88C5\u5668\u5305\u5185\u7F6E\u5FEB\u7167\uFF08--bundled\uFF09\u5B8C\u6210\u5B89\u88C5",
295
+ cannbot_delegate_fallback_local: "{reason}\uFF0C\u5DF2\u81EA\u52A8\u56DE\u9000\u672C\u4ED3 skills \u526F\u672C\u5B89\u88C5\uFF08\u526F\u672C\u51BB\u7ED3\u4E8E\u8FC1\u79FB\u524D\u7248\u672C\uFF0C\u540E\u7EED\u7531 cannbot \u4ED3\u7EDF\u4E00\u652F\u6301\uFF09",
296
+ cannbot_plugin_no_local_copy: "\u63D2\u4EF6 {plugin} \u5DF2\u8FC1\u79FB\u81F3 cannbot \u4ED3\u4E14\u672C\u4ED3\u65E0\u672C\u5730\u526F\u672C\u53EF\u56DE\u9000\uFF0C\u8BF7\u7B49\u5F85 cannbot \u5B89\u88C5\u5668\u6269\u5145\u5DE5\u5177/\u7EA7\u522B\u652F\u6301",
295
297
  cannbot_migrated_symlink: "\u68C0\u6D4B\u5230 {file} \u4E3A\u65E7\u7248\u63D2\u4EF6\u8F6F\u94FE\uFF0C\u5DF2\u8F6C\u4E3A\u771F\u5B9E\u6587\u4EF6\uFF08\u5185\u5BB9\u4FDD\u7559\u5E76\u5DF2\u5907\u4EFD\uFF09",
296
298
  cannbot_migrate_symlink_failed: "\u65E7\u7248\u8F6F\u94FE {file} \u8F6C\u771F\u5B9E\u6587\u4EF6\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\u540E\u91CD\u8BD5",
297
299
  cannbot_dual_skill_copy: "\u4EE5\u4E0B Skills \u540C\u65F6\u5B58\u5728\u4E8E\u65B0\u65E7\u4E24\u5957\u5E03\u5C40\u4E2D\uFF0CAI \u5DE5\u5177\u4F1A\u770B\u5230\u4E24\u4EFD\u526F\u672C: {skills}",
@@ -416,7 +418,7 @@ var init_en_US = __esm({
416
418
  info_aliases: "Aliases",
417
419
  uninstall_not_found: "Not found",
418
420
  uninstall_no_record: "No install record found, may not be installed or record is corrupted",
419
- uninstall_no_record_hint: "For manual cleanup, delete related files in the tool's config directory (e.g. .opencode/, .claude/, .trae/, .cursor/, .codex/ with .agents/, .github/, .codeartsdoer/)",
421
+ uninstall_no_record_hint: "For manual cleanup, delete related files in the tool's config directory (e.g. .opencode/, .claude/, .trae/, .cursor/, .codex/ with .agents/, .github/, .codeartsdoer/, .qoder/ with .qoder-cn/, .lingma/)",
420
422
  uninstall_in_progress: "Uninstalling",
421
423
  uninstall_summary_format: "{name} (removed {files} files, {dirs} directories)",
422
424
  uninstall_files_gone: " files no longer exist, install record cleaned",
@@ -554,6 +556,8 @@ var init_en_US = __esm({
554
556
  cannbot_registry_missing: "No cannbot-plugin.json record found after installation",
555
557
  cannbot_delegate_failed: "The cannbot installer exited with code {code}; see the output above",
556
558
  cannbot_bundled_fallback: "The upstream installer predates the plugins-official rename (pending its next release); automatically fell back to the installer package's bundled snapshot (--bundled)",
559
+ cannbot_delegate_fallback_local: "{reason}; automatically fell back to the local skills-repo copy (frozen at the pre-migration version until the cannbot repo takes over)",
560
+ cannbot_plugin_no_local_copy: "Plugin {plugin} has migrated to the cannbot repo with no local copy to fall back to; wait for the cannbot installer to gain tool/level support",
557
561
  cannbot_migrated_symlink: "{file} was a legacy plugin symlink; converted to a real file (content kept, backup saved)",
558
562
  cannbot_migrate_symlink_failed: "Failed to convert the legacy symlink {file} to a real file; resolve it manually and retry",
559
563
  cannbot_dual_skill_copy: "These Skills exist in both the legacy and cannbot layouts, the AI tool will see two copies: {skills}",
@@ -625,6 +629,21 @@ var init_i18n = __esm({
625
629
  import { homedir } from "os";
626
630
  import { join as join2 } from "path";
627
631
  import { existsSync as existsSync2 } from "fs";
632
+ import { spawnSync } from "child_process";
633
+ function isQoderCliLayout() {
634
+ if (process.env.CANNBOT_QODER_LAYOUT === "cli") return true;
635
+ if (process.env.CANNBOT_QODER_LAYOUT === "ide") return false;
636
+ if (qoderCliLayoutCache === void 0) {
637
+ try {
638
+ const whichCmd = process.platform === "win32" ? "where" : "which";
639
+ const result = spawnSync(whichCmd, ["qodercn"], { timeout: 5e3 });
640
+ qoderCliLayoutCache = result.status === 0;
641
+ } catch {
642
+ qoderCliLayoutCache = false;
643
+ }
644
+ }
645
+ return qoderCliLayoutCache;
646
+ }
628
647
  function validateTool(tool) {
629
648
  if (!VALID_TOOLS.includes(tool)) {
630
649
  throw new Error(
@@ -675,6 +694,8 @@ function getConfigRoot(tool, level, base) {
675
694
  return join2(home, ".copilot");
676
695
  case "codearts":
677
696
  return join2(home, ".codeartsdoer");
697
+ case "qoder":
698
+ return isQoderCliLayout() ? process.env.QODERCN_CONFIG_DIR || join2(home, ".qoder-cn") : join2(home, ".lingma");
678
699
  default:
679
700
  throw new Error(
680
701
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -706,6 +727,8 @@ function getConfigRoot(tool, level, base) {
706
727
  return join2(baseDir, ".github");
707
728
  case "codearts":
708
729
  return join2(baseDir, ".codeartsdoer");
730
+ case "qoder":
731
+ return isQoderCliLayout() ? join2(baseDir, ".qoder") : join2(baseDir, ".lingma");
709
732
  default:
710
733
  throw new Error(
711
734
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -722,6 +745,9 @@ function getSkillsRoot(tool, level, base) {
722
745
  }
723
746
  return join2(base || process.cwd(), ".agents", "skills");
724
747
  }
748
+ if (tool === "qoder" && isQoderCliLayout() && level === "global") {
749
+ return join2(homedir(), ".agents", "skills");
750
+ }
725
751
  return join2(getConfigRoot(tool, level, base), "skills");
726
752
  }
727
753
  function getAgentsFileName(tool) {
@@ -739,12 +765,12 @@ function getCannbotConfigDir() {
739
765
  function getCannbotRepoPath() {
740
766
  return join2(getCannbotConfigDir(), "repo");
741
767
  }
742
- var VALID_TOOLS, VALID_LEVELS;
768
+ var VALID_TOOLS, VALID_LEVELS, qoderCliLayoutCache;
743
769
  var init_paths = __esm({
744
770
  "src/utils/paths.ts"() {
745
771
  "use strict";
746
772
  init_i18n();
747
- VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "codex", "copilot", "codearts"];
773
+ VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "codex", "copilot", "codearts", "qoder"];
748
774
  VALID_LEVELS = ["project", "global"];
749
775
  }
750
776
  });
@@ -1420,37 +1446,6 @@ var init_embedded_plugins = __esm({
1420
1446
  }
1421
1447
  ]
1422
1448
  },
1423
- {
1424
- id: "triton-op-generator",
1425
- dir: "plugins-official/triton-op-generator",
1426
- displayName: "Triton \u7B97\u5B50\u5F00\u53D1",
1427
- script: "init.sh",
1428
- aliases: [
1429
- "triton"
1430
- ],
1431
- skills: 8,
1432
- agents: 0,
1433
- description: "Triton-Ascend \u7B97\u5B50 6 \u9636\u6BB5\u81EA\u52A8\u751F\u6210\u4E0E\u4F18\u5316\uFF08\u63CF\u8FF0\u2192\u4EE3\u7801\u2192\u9A8C\u8BC1\u2192\u4F18\u5316\uFF09",
1434
- version: "1.0.2",
1435
- configFile: "AGENTS.md",
1436
- configRootConfigLink: false,
1437
- installSkills: [
1438
- {
1439
- dir: "ops",
1440
- skills: [
1441
- "triton-task-extractor",
1442
- "triton-op-designer",
1443
- "triton-op-coding",
1444
- "triton-op-verifier",
1445
- "triton-latency-optimizer",
1446
- "triton-precision-debug",
1447
- "npu-arch",
1448
- "triton-simulator-optimizer"
1449
- ]
1450
- }
1451
- ],
1452
- installAgents: []
1453
- },
1454
1449
  {
1455
1450
  id: "torch-compile",
1456
1451
  dir: "plugins-official/torch-compile",
@@ -1736,6 +1731,21 @@ async function detectCodeArts() {
1736
1731
  }
1737
1732
  return void 0;
1738
1733
  }
1734
+ async function detectQoder() {
1735
+ const cmdPath = await getCommandPath("qodercn");
1736
+ if (cmdPath) {
1737
+ const version = await getCommandVersion("qodercn");
1738
+ return { name: "qoder", version, path: cmdPath };
1739
+ }
1740
+ const home = homedir2();
1741
+ for (const dir of [".lingma", ".qoder-cn"]) {
1742
+ const configDir = join5(home, dir);
1743
+ if (existsSync6(configDir)) {
1744
+ return { name: "qoder", path: configDir };
1745
+ }
1746
+ }
1747
+ return void 0;
1748
+ }
1739
1749
  async function detectTools() {
1740
1750
  const detectors = [
1741
1751
  detectOpenCode,
@@ -1744,7 +1754,8 @@ async function detectTools() {
1744
1754
  detectCursor,
1745
1755
  detectCodex,
1746
1756
  detectCopilot,
1747
- detectCodeArts
1757
+ detectCodeArts,
1758
+ detectQoder
1748
1759
  ];
1749
1760
  const results = await Promise.allSettled(detectors.map((d) => d()));
1750
1761
  const tools = [];
@@ -1763,7 +1774,8 @@ function getToolDisplayName(tool) {
1763
1774
  cursor: "Cursor",
1764
1775
  codex: "Codex",
1765
1776
  copilot: "GitHub Copilot",
1766
- codearts: "CodeArts"
1777
+ codearts: "CodeArts",
1778
+ qoder: "Qoder"
1767
1779
  };
1768
1780
  return names[tool];
1769
1781
  }
@@ -3836,6 +3848,9 @@ function findOrphanedDelegatedRecords(target) {
3836
3848
  return orphans;
3837
3849
  }
3838
3850
 
3851
+ // src/core/cannbot-delegate.ts
3852
+ init_registry();
3853
+
3839
3854
  // src/core/installer.ts
3840
3855
  init_registry();
3841
3856
  init_manifest();
@@ -4374,6 +4389,18 @@ async function installViaManifest(plugin, repoPath, tool, level, installPath, pr
4374
4389
  continue;
4375
4390
  }
4376
4391
  const targetPath = join14(agentsDir, agentFile);
4392
+ if (tool === "qoder") {
4393
+ try {
4394
+ if (existsSync15(targetPath) || isSymlink(targetPath)) {
4395
+ removePath(targetPath);
4396
+ }
4397
+ copyFileSync2(agentPath, targetPath);
4398
+ installedAgents.push(agentFile);
4399
+ } catch {
4400
+ logger.warn(t("install_agent_failed").replace("{name}", agentFile));
4401
+ }
4402
+ continue;
4403
+ }
4377
4404
  const result = installLink(agentPath, targetPath);
4378
4405
  if (result !== "failed") {
4379
4406
  installedAgents.push(agentFile);
@@ -4946,14 +4973,45 @@ async function delegateInstall(options) {
4946
4973
  async function installPluginRouted(options) {
4947
4974
  const isCannbot = options.source === "cannbot" || options.source !== "skills" && options.plugin?.source === "cannbot";
4948
4975
  if (isCannbot) {
4949
- return delegateInstall({
4976
+ const boundary = boundaryErrors(options.tool, options.level);
4977
+ if (boundary.length === 0) {
4978
+ return delegateInstall({
4979
+ pluginId: options.pluginId,
4980
+ displayName: options.plugin?.displayName,
4981
+ tool: options.tool,
4982
+ level: options.level,
4983
+ target: options.installPath || process.cwd(),
4984
+ yes: options.yes
4985
+ });
4986
+ }
4987
+ if (options.source === "cannbot") {
4988
+ return {
4989
+ success: false,
4990
+ pluginId: options.pluginId,
4991
+ skillsCount: 0,
4992
+ agentsCount: 0,
4993
+ errors: boundary,
4994
+ warnings: []
4995
+ };
4996
+ }
4997
+ const local = findPlugin(options.pluginId, { source: "skills" });
4998
+ if (local) {
4999
+ const result = await installPlugin({ ...options, plugin: local });
5000
+ if (result.success) {
5001
+ result.warnings.unshift(
5002
+ t("cannbot_delegate_fallback_local").replace("{reason}", boundary.join("\uFF1B"))
5003
+ );
5004
+ }
5005
+ return result;
5006
+ }
5007
+ return {
5008
+ success: false,
4950
5009
  pluginId: options.pluginId,
4951
- displayName: options.plugin?.displayName,
4952
- tool: options.tool,
4953
- level: options.level,
4954
- target: options.installPath || process.cwd(),
4955
- yes: options.yes
4956
- });
5010
+ skillsCount: 0,
5011
+ agentsCount: 0,
5012
+ errors: [...boundary, t("cannbot_plugin_no_local_copy").replace("{plugin}", options.pluginId)],
5013
+ warnings: []
5014
+ };
4957
5015
  }
4958
5016
  return installPlugin(options);
4959
5017
  }
@@ -7354,13 +7412,13 @@ function createCLI() {
7354
7412
  program2.command("status").description("Show installed plugins").action(async () => {
7355
7413
  await statusCommand();
7356
7414
  });
7357
- 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("-s, --source <source>", "Plugin source for same-name plugins (cannbot, skills)").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) => {
7415
+ 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, qoder)").option("-l, --level <level>", "Install level (project, global)", "project").option("-s, --source <source>", "Plugin source for same-name plugins (cannbot, skills)").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) => {
7358
7416
  await installCommand(names, options);
7359
7417
  });
7360
- 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) => {
7418
+ 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, qoder)").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) => {
7361
7419
  await uninstallCommand(names, options);
7362
7420
  });
7363
- 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) => {
7421
+ program2.command("update [plugins...]").description("Update installed plugins (git pull + reinstall)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, codex, copilot, codearts, qoder)").option("-l, --level <level>", "Install level (project, global)").option("-y, --yes", "Skip confirmation prompts").action(async (plugins, options) => {
7364
7422
  await updateCommand(plugins, options);
7365
7423
  });
7366
7424
  program2.command("info <plugin>").description("Show plugin details").action(async (plugin) => {