@vibeapi/cli 0.0.55 → 0.0.56

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.
@@ -91,5 +91,7 @@ export declare function getClaudeCodeTierChains(): Record<string, string[]>;
91
91
  export declare function getClaudeDesktopRules(): ClaudeDesktopRules;
92
92
  export declare function getGatewayModelRules(): GatewayModelRules;
93
93
  export declare function getCodexRules(): CodexRules;
94
+ /** Compare dotted numeric versions (`2.1.9` < `2.1.10`); missing parts count as 0. */
95
+ export declare function compareVersions(a: string, b: string): number;
94
96
  export declare function getToolMinVersion(toolName: string): string | null;
95
97
  export declare function reloadRegistry(): void;
@@ -1 +1 @@
1
- import{dirname as e,join as o}from"path";import{fileURLToPath as t}from"url";import{existsSync as n,readFileSync as r}from"fs";const l=e(t(import.meta.url));let s=null;function u(){return s||(s=function(){const e=[o(l,"..","..","models.json"),o(l,"..","models.json"),o(l,"models.json")];for(const o of e)if(n(o))return JSON.parse(r(o,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}()),s}export function getDefaultModels(){return{...u().defaultModels}}export function isRetiredDefaultModel(e,o){return u().retiredDefaultModels?.[e]?.includes(o)??!1}export function getDefaultToolModel(){return u().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const o=u().toolDefaults;return o&&Object.prototype.hasOwnProperty.call(o,e)?(o[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...u().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=u().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,o])=>[e,[...o]]))}export function getClaudeDesktopRules(){const e=u().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=u().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e}))}}export function getCodexRules(){return{standardContextWindow:u().codex?.standardContextWindow??272e3}}export function getToolMinVersion(e){return u().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){s=null}
1
+ import{dirname as e,join as o}from"path";import{fileURLToPath as t}from"url";import{existsSync as n,readFileSync as r}from"fs";const l=e(t(import.meta.url));let s=null;function u(){return s||(s=function(){const e=[o(l,"..","..","models.json"),o(l,"..","models.json"),o(l,"models.json")];for(const o of e)if(n(o))return JSON.parse(r(o,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}()),s}export function getDefaultModels(){return{...u().defaultModels}}export function isRetiredDefaultModel(e,o){return u().retiredDefaultModels?.[e]?.includes(o)??!1}export function getDefaultToolModel(){return u().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const o=u().toolDefaults;return o&&Object.prototype.hasOwnProperty.call(o,e)?(o[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...u().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=u().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,o])=>[e,[...o]]))}export function getClaudeDesktopRules(){const e=u().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=u().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e}))}}export function getCodexRules(){return{standardContextWindow:u().codex?.standardContextWindow??272e3}}export function compareVersions(e,o){const t=e.split(".").map(e=>parseInt(e,10)||0),n=o.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(t.length,n.length);e++){const o=(t[e]??0)-(n[e]??0);if(0!==o)return o}return 0}export function getToolMinVersion(e){return u().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){s=null}
@@ -2,6 +2,8 @@ import { type VibecliModels } from './config.js';
2
2
  import { type BackupEntry, type RestoreResult } from './tools/backup.js';
3
3
  import type { ApplyNote } from './tools/types.js';
4
4
  import { type ModelCatalog } from './model-catalog.js';
5
+ import { compareVersions } from './model-registry.js';
6
+ export { compareVersions };
5
7
  export interface ToolRestoreEntry {
6
8
  file: string;
7
9
  result: RestoreResult;
@@ -89,6 +91,4 @@ export declare class ToolManager {
89
91
  getSupportedTools(): ToolInfo[];
90
92
  isGitInstalled(): boolean;
91
93
  }
92
- /** Compare dotted numeric versions (`2.1.9` < `2.1.10`); missing parts count as 0. */
93
- export declare function compareVersions(a: string, b: string): number;
94
94
  export declare const toolManager: ToolManager;
@@ -1 +1 @@
1
- import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import l from"inquirer";import e from"chalk";import s from"terminal-link";import i from"ora";import{logger as r}from"../utils/logger.js";import{configManager as a}from"./config.js";import{getAdapter as c,listAdapters as d,TOOL_ADAPTERS as u}from"./tools/registry.js";import{backupBeforeWrite as g,listBackups as m,restoreBackup as p}from"./tools/backup.js";import{existsSync as f,rmSync as w}from"fs";import{stringWidth as h}from"../utils/string-width.js";import{resolveModelCatalog as _}from"./model-catalog.js";import{getToolMinVersion as y}from"./model-registry.js";function P(o){const t=u[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(u).map(o=>[o,P(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;const l=c(t);if(l?.isInstalled)try{return l.isInstalled()}catch{return!1}try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}async installTool(t){const a=SUPPORTED_TOOLS[t];if(!a)throw new Error(`Unknown tool: ${t}`);const c=i(n.t("wizard.installing_tool")).start();try{c.info(e.gray("$ ")+e.white(a.installCommand)),c.stop(),o(a.installCommand,{stdio:"inherit"}),c.succeed(n.t("wizard.tool_installed"))}catch(i){c.fail(n.t("wizard.install_failed"));const d=(i.message||"")+(i.stderr?.toString()||"")+(i.stdout?.toString()||"");if(!(d.includes("EACCES")||d.includes("permission denied")||d.includes("EPERM")||243===i.status))throw new Error(`Failed to install ${a.displayName}: ${i}`);if(console.log("\n⚠️ "+n.t("install.permission_detected")+"\n"),"win32"===process.platform)try{const t=a.installCommand.replace("npm install -g","npm install -g --force");return console.log("🔧 "+n.t("install.trying_solution",{num:"1",desc:n.t("install.using_force")})),console.log(e.gray("$ ")+e.white(t)),o(t,{stdio:"inherit"}),void console.log("\n✅ "+n.t("install.permission_fixed"))}catch(o){r.warn("Retry install failed:",o),console.log("\n❌ "+n.t("install.auto_fix_failed")),console.log(e.yellow("\n📌 "+n.t("install.windows_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_1_title"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step1"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step2"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step3"))),console.log(e.white(` ${a.installCommand}`)),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_2_title"))),console.log(e.gray(" "+n.t("install.windows_solution_2_command"))),console.log(e.white(` ${a.installCommand.replace("npm install -g","npm install -g --prefix=%APPDATA%\\npm")}`)),console.log("");const{action:s}=await l.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===s)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);return void console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}console.log(e.yellow("\n📌 "+n.t("install.unix_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.unix_solution_1_title"))),console.log(e.gray(" "+n.t("install.unix_solution_1_desc"))),console.log(e.white(` sudo ${a.installCommand}`)),console.log("");const u="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally",g=s(u,u,{fallback:()=>u});console.log(e.cyan.bold(n.t("install.unix_solution_2_title"))),console.log(e.gray(" "+n.t("install.unix_solution_2_desc"))),console.log(e.blue(" 📖 "+n.t("install.npm_docs_link")+": ")+g),console.log("");const{action:m}=await l.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===m)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}}getToolConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return r.warn(`Failed to read config for ${o}:`,t),r.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=c(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),l=[];for(const o of n)f(o)&&(g(o),w(o,{force:!0}),l.push(o));return l}loadPrivateConfig(o,t,n,l,e={}){const s=c(o);if(!s)throw new Error(`Unknown tool: ${o}`);e.force&&this.forceResetConfig(o),s.loadPrivateConfig({apiKey:t,baseUrl:a.getBaseUrl(),models:n,settings:a.getToolSettings(o),...l?{catalog:l}:{}})}async applyPrivateConfig(o,t,n,l={}){const e=c(o);if(!e)throw new Error(`Unknown tool: ${o}`);const s=e.wantsModelCatalog?await _(t):null;l.force?this.loadPrivateConfig(o,t,n,s??void 0,{force:!0}):s?this.loadPrivateConfig(o,t,n,s):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=c(o);if(!t)return[];const l=[];try{t.applyNotes&&l.push(...t.applyNotes())}catch(t){r.logError(`ToolManager.applyNotes(${o})`,t)}const e=this.outdatedVersion(o);return e&&l.push({kind:"action",text:n.t("tools.version_outdated",{current:e.current,min:e.min,upgrade:t.upgradeCommand||t.installCommand})}),l}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,l=this.applyNotes(o);for(const o of l.filter(o=>"detail"===o.kind))r.record(`${n}: ${o.text}`);const s=l.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),i=" ".repeat(Math.max(1,t-h(n)));console.log(e.green("√ "+n)+(s?i+s:""));for(const o of l.filter(o=>"action"===o.kind))console.log(e.yellow(" ! "+o.text))}installedVersion(o){const n=c(o);if(!n)return null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return r.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},l=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return l?l[0]:null}catch{return null}}outdatedVersion(o){const t=y(o);if(!t)return null;const n=this.installedVersion(o);return n&&compareVersions(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);t.unloadPrivateConfig()}async clearPinnedModels(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(a.setToolModel(o,null),!t.clearPinnedModels)return[];const n=a.getApiKeyForTool(o),l=t.wantsModelCatalog&&n?await _(n):null;return t.clearPinnedModels(l??void 0)}supportsClearPinnedModels(o){return Boolean(c(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:m(o)}))}restorePrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:p(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return d().filter(o=>!o.hidden).map(o=>P(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export function compareVersions(o,t){const n=o.split(".").map(o=>parseInt(o,10)||0),l=t.split(".").map(o=>parseInt(o,10)||0);for(let o=0;o<Math.max(n.length,l.length);o++){const t=(n[o]??0)-(l[o]??0);if(0!==t)return t}return 0}export const toolManager=ToolManager.getInstance();
1
+ import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import l from"inquirer";import e from"chalk";import s from"terminal-link";import i from"ora";import{logger as r}from"../utils/logger.js";import{configManager as a}from"./config.js";import{getAdapter as c,listAdapters as d,TOOL_ADAPTERS as u}from"./tools/registry.js";import{backupBeforeWrite as g,listBackups as m,restoreBackup as p}from"./tools/backup.js";import{existsSync as f,rmSync as w}from"fs";import{stringWidth as h}from"../utils/string-width.js";import{resolveModelCatalog as _}from"./model-catalog.js";import{compareVersions as y,getToolMinVersion as P}from"./model-registry.js";export{y as compareVersions};function C(o){const t=u[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(u).map(o=>[o,C(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;const l=c(t);if(l?.isInstalled)try{return l.isInstalled()}catch{return!1}try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}async installTool(t){const a=SUPPORTED_TOOLS[t];if(!a)throw new Error(`Unknown tool: ${t}`);const c=i(n.t("wizard.installing_tool")).start();try{c.info(e.gray("$ ")+e.white(a.installCommand)),c.stop(),o(a.installCommand,{stdio:"inherit"}),c.succeed(n.t("wizard.tool_installed"))}catch(i){c.fail(n.t("wizard.install_failed"));const d=(i.message||"")+(i.stderr?.toString()||"")+(i.stdout?.toString()||"");if(!(d.includes("EACCES")||d.includes("permission denied")||d.includes("EPERM")||243===i.status))throw new Error(`Failed to install ${a.displayName}: ${i}`);if(console.log("\n⚠️ "+n.t("install.permission_detected")+"\n"),"win32"===process.platform)try{const t=a.installCommand.replace("npm install -g","npm install -g --force");return console.log("🔧 "+n.t("install.trying_solution",{num:"1",desc:n.t("install.using_force")})),console.log(e.gray("$ ")+e.white(t)),o(t,{stdio:"inherit"}),void console.log("\n✅ "+n.t("install.permission_fixed"))}catch(o){r.warn("Retry install failed:",o),console.log("\n❌ "+n.t("install.auto_fix_failed")),console.log(e.yellow("\n📌 "+n.t("install.windows_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_1_title"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step1"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step2"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step3"))),console.log(e.white(` ${a.installCommand}`)),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_2_title"))),console.log(e.gray(" "+n.t("install.windows_solution_2_command"))),console.log(e.white(` ${a.installCommand.replace("npm install -g","npm install -g --prefix=%APPDATA%\\npm")}`)),console.log("");const{action:s}=await l.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===s)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);return void console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}console.log(e.yellow("\n📌 "+n.t("install.unix_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.unix_solution_1_title"))),console.log(e.gray(" "+n.t("install.unix_solution_1_desc"))),console.log(e.white(` sudo ${a.installCommand}`)),console.log("");const u="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally",g=s(u,u,{fallback:()=>u});console.log(e.cyan.bold(n.t("install.unix_solution_2_title"))),console.log(e.gray(" "+n.t("install.unix_solution_2_desc"))),console.log(e.blue(" 📖 "+n.t("install.npm_docs_link")+": ")+g),console.log("");const{action:m}=await l.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===m)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}}getToolConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return r.warn(`Failed to read config for ${o}:`,t),r.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=c(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),l=[];for(const o of n)f(o)&&(g(o),w(o,{force:!0}),l.push(o));return l}loadPrivateConfig(o,t,n,l,e={}){const s=c(o);if(!s)throw new Error(`Unknown tool: ${o}`);e.force&&this.forceResetConfig(o),s.loadPrivateConfig({apiKey:t,baseUrl:a.getBaseUrl(),models:n,settings:a.getToolSettings(o),...l?{catalog:l}:{}})}async applyPrivateConfig(o,t,n,l={}){const e=c(o);if(!e)throw new Error(`Unknown tool: ${o}`);const s=e.wantsModelCatalog?await _(t):null;l.force?this.loadPrivateConfig(o,t,n,s??void 0,{force:!0}):s?this.loadPrivateConfig(o,t,n,s):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=c(o);if(!t)return[];const l=[];try{t.applyNotes&&l.push(...t.applyNotes())}catch(t){r.logError(`ToolManager.applyNotes(${o})`,t)}const e=this.outdatedVersion(o);if(e){l.push({kind:"action",text:n.t("tools.version_outdated",{current:e.current,min:e.min,upgrade:t.currentUpgradeCommand?.()||t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(e.min)??[])l.push({kind:"action",text:o})}return l}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,l=this.applyNotes(o);for(const o of l.filter(o=>"detail"===o.kind))r.record(`${n}: ${o.text}`);const s=l.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),i=" ".repeat(Math.max(1,t-h(n)));console.log(e.green("√ "+n)+(s?i+s:""));for(const o of l.filter(o=>"action"===o.kind))console.log(e.yellow(" ! "+o.text))}installedVersion(o){const n=c(o);if(!n)return null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return r.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},l=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return l?l[0]:null}catch{return null}}outdatedVersion(o){const t=P(o);if(!t)return null;const n=this.installedVersion(o);return n&&y(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);t.unloadPrivateConfig()}async clearPinnedModels(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(a.setToolModel(o,null),!t.clearPinnedModels)return[];const n=a.getApiKeyForTool(o),l=t.wantsModelCatalog&&n?await _(n):null;return t.clearPinnedModels(l??void 0)}supportsClearPinnedModels(o){return Boolean(c(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:m(o)}))}restorePrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:p(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return d().filter(o=>!o.hidden).map(o=>C(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
@@ -1 +1 @@
1
- import{join as e}from"path";import{claudeCodeManager as t}from"../claude-code-manager.js";import{backupBeforeWrite as o}from"./backup.js";import{i18n as a}from"../i18n.js";import{gatewayModelSpecs as n,prettyModelName as d,vendorNames as i}from"../gateway-models.js";import{toolHome as s}from"./types.js";const l=e(s(),".claude","settings.json"),r=e(s(),".claude.json");let c;export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:"npm install -g @anthropic-ai/claude-code",upgradeCommand:"claude update",configPath:l,wantsModelCatalog:!0,loadPrivateConfig(e){o(l),o(r),c=function(e){if(!e)return;const t=new Set(e.models);return n("claude-code",e.clientModels).filter(e=>t.has(e.id))}(e.catalog),t.loadPrivateConfig(e.apiKey,e.models,e.catalog?.models,c)},unloadPrivateConfig(){o(l),t.unloadPrivateConfig()},detectCurrentConfig:()=>t.detectCurrentConfig(),getConfig:()=>({settings:t.getSettings(),mcp:t.getMCPConfig()}),updateConfig(e){const o=e||{};o.settings&&t.saveSettings(o.settings),o.mcp&&t.saveMCPConfig(o.mcp)},clearPinnedModels:e=>(o(l),t.clearPinnedModels(e?.models)),applyNotes(){const e=[];c&&c.length>0&&(e.push({kind:"summary",text:a.t("tools.claude_code.gateway_models",{count:String(c.length),vendors:i(c.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:c.map(e=>e.name||d(e.id)).join(", ")}));for(const o of t.getLastTierFallbacks())e.push({kind:"detail",text:a.t("tools.claude_code.tier_fallback",{tier:o.tier,from:o.from,to:o.to})});return e},backupPaths:()=>[l,r],forceResetPaths:()=>[l]};
1
+ import{join as e}from"path";import{claudeCodeManager as t}from"../claude-code-manager.js";import{backupBeforeWrite as o}from"./backup.js";import{i18n as n}from"../i18n.js";import{gatewayModelSpecs as a,prettyModelName as i,vendorNames as l}from"../gateway-models.js";import{compareVersions as s}from"../model-registry.js";import{toolHome as d}from"./types.js";import{CLAUDE_NPM_MIRROR_INSTALL as r,CLAUDE_NPM_UNINSTALL as c,claudeUpdateChannel as m,findClaudeInstalls as u}from"./claude-installs.js";const p=e(d(),".claude","settings.json"),g=e(d(),".claude.json");let f;function C(e){return`${n.t(`tools.claude_code.install_kind.${e.kind}`)} ${e.version??"?"} (${e.path})`}export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:"npm install -g @anthropic-ai/claude-code",upgradeCommand:"claude update",installedVersion:()=>u()[0]?.version??null,currentUpgradeCommand:()=>"npm"===u()[0]?.kind?r:"claude update",upgradeHints(e){const t=[];return"npm"!==u()[0]?.kind&&t.push(n.t("tools.claude_code.upgrade_fallback",{mirror:r})),"stable"===m()&&t.push(n.t("tools.claude_code.stable_channel",{min:e})),t},configPath:p,wantsModelCatalog:!0,loadPrivateConfig(e){o(p),o(g),f=function(e){if(!e)return;const t=new Set(e.models);return a("claude-code",e.clientModels).filter(e=>t.has(e.id))}(e.catalog),t.loadPrivateConfig(e.apiKey,e.models,e.catalog?.models,f)},unloadPrivateConfig(){o(p),t.unloadPrivateConfig()},detectCurrentConfig:()=>t.detectCurrentConfig(),getConfig:()=>({settings:t.getSettings(),mcp:t.getMCPConfig()}),updateConfig(e){const o=e||{};o.settings&&t.saveSettings(o.settings),o.mcp&&t.saveMCPConfig(o.mcp)},clearPinnedModels:e=>(o(p),t.clearPinnedModels(e?.models)),applyNotes(){const e=[],o=u();if(o.length>1){e.push({kind:"action",text:n.t("tools.claude_code.multiple_installs",{count:String(o.length),active:C(o[0]),others:o.slice(1).map(C).join("、")})});const t=o.find(e=>"native"===e.kind),a=o.find(e=>"npm"===e.kind);if(t&&a){const o=!!a.version&&s(a.version,t.version??"0")>0;e.push({kind:"action",text:o?n.t("tools.claude_code.keep_npm",{mirror:r}):n.t("tools.claude_code.keep_native",{uninstall:c})})}}f&&f.length>0&&(e.push({kind:"summary",text:n.t("tools.claude_code.gateway_models",{count:String(f.length),vendors:l(f.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:f.map(e=>e.name||i(e.id)).join(", ")}));for(const o of t.getLastTierFallbacks())e.push({kind:"detail",text:n.t("tools.claude_code.tier_fallback",{tier:o.tier,from:o.from,to:o.to})});return e},backupPaths:()=>[p,g],forceResetPaths:()=>[p]};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Every copy of Claude Code a terminal could start. Users often end up with both
3
+ * the official native install (`~/.local/bin/claude`, updated by `claude update`)
4
+ * and an npm global one; only the first on PATH runs, and `claude update` only
5
+ * updates that one.
6
+ */
7
+ export interface ClaudeInstall {
8
+ path: string;
9
+ kind: 'native' | 'npm' | 'other';
10
+ version: string | null;
11
+ }
12
+ /** Same package, same binary (npm ships the native build as an optional dependency); npmmirror is reachable from mainland China. */
13
+ export declare const CLAUDE_NPM_MIRROR_INSTALL = "npm install -g @anthropic-ai/claude-code@latest --registry=https://registry.npmmirror.com";
14
+ export declare const CLAUDE_NPM_UNINSTALL = "npm uninstall -g @anthropic-ai/claude-code";
15
+ /** Tests swap in a fake `<path> --version`. */
16
+ export declare function setClaudeVersionRunnerForTests(fake: (path: string) => string): void;
17
+ /** In PATH order (the first one is what `claude` starts), one entry per real file. Probed once per run. */
18
+ export declare function findClaudeInstalls(): ClaudeInstall[];
19
+ /** `autoUpdatesChannel` in ~/.claude/settings.json; unset means `latest`. */
20
+ export declare function claudeUpdateChannel(): string;
@@ -0,0 +1 @@
1
+ import{spawnSync as t}from"child_process";import{existsSync as e,readFileSync as n,realpathSync as o,statSync as r}from"fs";import{delimiter as s,dirname as i,isAbsolute as c,join as a}from"path";import{toolHome as l}from"./types.js";export const CLAUDE_NPM_MIRROR_INSTALL="npm install -g @anthropic-ai/claude-code@latest --registry=https://registry.npmmirror.com";export const CLAUDE_NPM_UNINSTALL="npm uninstall -g @anthropic-ai/claude-code";let u=e=>{const n={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]};return`${(/\.cmd$/i.test(e)?t(`"${e}" --version`,{...n,shell:!0}):t(e,["--version"],n)).stdout??""}`};export function setClaudeVersionRunnerForTests(t){u=t,f=null}function p(t){try{return r(t).isFile()}catch{return!1}}function d(t){if(n=i(t),r=a(l(),".local","bin"),"win32"===process.platform?n.toLowerCase()===r.toLowerCase():n===r)return"native";var n,r;const s=a("node_modules","@anthropic-ai","claude-code");if(e(a(i(t),s)))return"npm";try{if(o(t).includes(s))return"npm"}catch{}return"other"}let f=null;export function findClaudeInstalls(){if(f)return f;const t="win32"===process.platform?["claude.exe","claude.cmd"]:["claude"],e=new Set,n=[];for(const r of(process.env.PATH??"").split(s))if(r&&c(r))for(const s of t){const t=a(r,s);if(!p(t))continue;let i=t;try{i=o(t)}catch{}const c="win32"===process.platform?i.toLowerCase():i;if(e.has(c))continue;e.add(c);const l=u(t).match(/(\d+)\.(\d+)\.(\d+)/);n.push({path:t,kind:d(t),version:l?l[0]:null})}return f=n,n}export function claudeUpdateChannel(){try{const t=JSON.parse(n(a(l(),".claude","settings.json"),"utf-8"));return"string"==typeof t.autoUpdatesChannel?t.autoUpdatesChannel:"latest"}catch{return"latest"}}
@@ -49,6 +49,10 @@ export interface ToolAdapter {
49
49
  installCommand: string;
50
50
  /** Shell command that upgrades an installed copy; defaults to `installCommand`. */
51
51
  upgradeCommand?: string;
52
+ /** Upgrade command for the copy that actually runs, when it depends on how it was installed; else `upgradeCommand`. */
53
+ currentUpgradeCommand?(): string;
54
+ /** Extra lines shown under the "too old" note (fallback when the upgrade can't connect, channel caveats). */
55
+ upgradeHints?(min: string): string[];
52
56
  /**
53
57
  * Installed version as `x.y.z`, for tools without a `--version` CLI (GUI
54
58
  * apps); null when unknown. Checked against `models.json` → `toolMinVersions`.
@@ -359,7 +359,17 @@
359
359
  },
360
360
  "claude_code": {
361
361
  "gateway_models": "{{count}} Chinese models added to /model ({{vendors}})",
362
- "tier_fallback": "This key can't use Claude Code's default {{from}}; the {{tier}} alias now uses {{to}}"
362
+ "tier_fallback": "This key can't use Claude Code's default {{from}}; the {{tier}} alias now uses {{to}}",
363
+ "multiple_installs": "{{count}} copies of Claude Code found; typing claude runs only {{active}}; also present: {{others}}",
364
+ "keep_native": "Keep only the official native install: run {{uninstall}} to remove the npm copy, then upgrade with claude update",
365
+ "upgrade_fallback": "If claude update cannot reach the download server, install from the npm mirror instead: {{mirror}}",
366
+ "stable_channel": "Your update channel in settings.json is stable, which may not have reached {{min}} yet; set autoUpdatesChannel to latest, then upgrade",
367
+ "install_kind": {
368
+ "native": "native",
369
+ "npm": "npm",
370
+ "other": "other"
371
+ },
372
+ "keep_npm": "Keep only the npm copy: delete the native install (~/.local/bin/claude and ~/.local/share/claude), then upgrade with {{mirror}}"
363
373
  },
364
374
  "model_family": {
365
375
  "gpt": "GPT",
@@ -359,7 +359,17 @@
359
359
  },
360
360
  "claude_code": {
361
361
  "gateway_models": "/model 菜单加入 {{count}} 个国产模型({{vendors}})",
362
- "tier_fallback": "当前 Key 用不了 Claude Code 默认的 {{from}},{{tier}} 档已改用 {{to}}"
362
+ "tier_fallback": "当前 Key 用不了 Claude Code 默认的 {{from}},{{tier}} 档已改用 {{to}}",
363
+ "multiple_installs": "本机有 {{count}} 份 Claude Code,终端里输入 claude 只会运行 {{active}},另外还有 {{others}}",
364
+ "keep_native": "建议只留官方原生安装:运行 {{uninstall}} 删掉 npm 那份,之后用 claude update 升级",
365
+ "upgrade_fallback": "claude update 连不上下载服务器时,改用国内 npm 镜像安装:{{mirror}}",
366
+ "stable_channel": "settings.json 里的更新渠道是 stable,这个渠道可能还没到 {{min}};把 autoUpdatesChannel 改成 latest 后再升级",
367
+ "install_kind": {
368
+ "native": "原生安装",
369
+ "npm": "npm 安装",
370
+ "other": "其他安装"
371
+ },
372
+ "keep_npm": "建议只留 npm 那份:删除原生安装(~/.local/bin/claude 与 ~/.local/share/claude),之后用 {{mirror}} 升级"
363
373
  },
364
374
  "model_family": {
365
375
  "gpt": "GPT",
package/dist/models.json CHANGED
@@ -6,8 +6,9 @@
6
6
  "reasoning": "claude-opus-5-5[1m]"
7
7
  },
8
8
  "retiredDefaultModels": {
9
- "opus": ["claude-opus-4-8[1m]"],
10
- "reasoning": ["claude-opus-4-8[1m]"]
9
+ "opus": ["claude-opus-4-6", "claude-opus-4-8[1m]"],
10
+ "sonnet": ["claude-sonnet-4-6"],
11
+ "reasoning": ["claude-opus-4-6", "claude-opus-4-8[1m]"]
11
12
  },
12
13
  "defaultToolModel": "gpt-5.5",
13
14
  "toolDefaults": {
package/models.json CHANGED
@@ -6,8 +6,9 @@
6
6
  "reasoning": "claude-opus-5-5[1m]"
7
7
  },
8
8
  "retiredDefaultModels": {
9
- "opus": ["claude-opus-4-8[1m]"],
10
- "reasoning": ["claude-opus-4-8[1m]"]
9
+ "opus": ["claude-opus-4-6", "claude-opus-4-8[1m]"],
10
+ "sonnet": ["claude-sonnet-4-6"],
11
+ "reasoning": ["claude-opus-4-6", "claude-opus-4-8[1m]"]
11
12
  },
12
13
  "defaultToolModel": "gpt-5.5",
13
14
  "toolDefaults": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.55",
3
+ "version": "0.0.56",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",