@vibeapi/cli 0.0.78 → 0.0.81
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 +4 -4
- package/dist/commands/setup.js +1 -1
- package/dist/lib/env-cleanup.d.ts +2 -0
- package/dist/lib/env-cleanup.js +1 -1
- package/dist/lib/persistent-env.d.ts +13 -0
- package/dist/lib/persistent-env.js +1 -0
- package/dist/lib/tool-manager.js +1 -1
- package/dist/lib/tool-upgrade.js +1 -1
- package/dist/lib/tools/antigravity.d.ts +2 -0
- package/dist/lib/tools/antigravity.js +1 -0
- package/dist/lib/tools/backup.d.ts +1 -1
- package/dist/lib/tools/backup.js +1 -1
- package/dist/lib/tools/registry.js +1 -1
- package/dist/lib/tools/tool-installs.d.ts +12 -3
- package/dist/lib/tools/tool-installs.js +1 -1
- package/dist/locales/en_US.json +7 -2
- package/dist/locales/zh_CN.json +7 -2
- package/dist/models.json +2 -1
- package/models.json +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @vibeapi/api-helper
|
|
2
2
|
|
|
3
|
-
> 一条命令,在 Claude Code / Claude Desktop / Codex / OpenClaw / Hermes / AtomCode / Grok Build 之间统一配置 API Key 与模型。
|
|
3
|
+
> 一条命令,在 Claude Code / Claude Desktop / Codex / OpenClaw / Hermes / AtomCode / Grok Build / Antigravity CLI 之间统一配置 API Key 与模型。
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@vibeapi/api-helper)
|
|
6
6
|
[](https://nodejs.org)
|
|
@@ -36,7 +36,7 @@ npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@l
|
|
|
36
36
|
vibecli setup --key sk-xxx
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code(机器上装了 Claude Desktop 也一并配好)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
|
|
39
|
+
`--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code(机器上装了 Claude Desktop 也一并配好)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、机器上装了 Antigravity CLI(`agy`)且有 Gemini 模型就配 agy。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d
|
|
@@ -50,7 +50,7 @@ vibecli setup --1m
|
|
|
50
50
|
vibecli setup --no-1m
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
配完直接运行 `claude` / `codex` / `grok`
|
|
53
|
+
配完直接运行 `claude` / `codex` / `grok` 即可(agy 要新开一个终端)。Claude Desktop 默认隐藏官方(Claude.ai 账号)登录入口、只走网关,想保留就加 `--claude-official on`。
|
|
54
54
|
|
|
55
55
|
### 方式 B:交互式向导
|
|
56
56
|
|
|
@@ -76,7 +76,7 @@ vibecli config claude-code clear-model # 模型选择被钉住时,交还给
|
|
|
76
76
|
|
|
77
77
|
## 能做什么
|
|
78
78
|
|
|
79
|
-
- **多工具一键配置**:把当前 API Key / 模型注入 Claude Code、Claude Desktop(桌面端第三方推理模式,写应用本地配置库,无需管理员 / 描述文件)、Codex、OpenClaw、Hermes、AtomCode、Grok Build(OpenCode 暂时下架,`vibecli config opencode` 仍可用)。
|
|
79
|
+
- **多工具一键配置**:把当前 API Key / 模型注入 Claude Code、Claude Desktop(桌面端第三方推理模式,写应用本地配置库,无需管理员 / 描述文件)、Codex、OpenClaw、Hermes、AtomCode、Grok Build、Antigravity CLI(OpenCode 暂时下架,`vibecli config opencode` 仍可用)。
|
|
80
80
|
- **按工具选模型**:使用默认 / 实时从 API 拉取 / 内置预设 / 手动输入;每个工具可用不同模型。
|
|
81
81
|
- Claude Code 用默认模型时不写 `ANTHROPIC_*_MODEL` 环境变量,顶层 `model` 由 `settings-template.json` 提供(当前为 `opus[1m]`);显式选择其它模型时会覆盖该模板值。Codex 默认 `gpt-6-astra`,Grok Build 默认 `grok-4.6`,其余工具默认 `gpt-5.5`。
|
|
82
82
|
- Codex(CLI 与桌面版)的模型菜单除自带的 GPT 模型外,还列出网关的 Claude、Gemini 与国产模型(只列 Key 能用的);Claude Code 的 `/model` 菜单也会在内置档位后列出 Key 能用的国产模型;每个模型按自己的上下文窗口设置,窗口用到 80% 时自动压缩。默认启用 1M 上下文,交互配置 Codex 时可取消(取消后窗口不超过 272K)。需要 Codex 0.122 及以上;Codex、Claude Code 版本过旧时,配置完成会提示升级命令。
|
package/dist/commands/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"chalk";import{getAdapter as o}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as s}from"./base.js";import{i18n as i}from"../lib/i18n.js";import{configManager as a}from"../lib/config.js";import{toolManager as l,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as d,fetchModels as r}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as p,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";async function g(e){const o=await r(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),probed:!0}}function k(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}export function parseOnOff(e){const o=(e??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(o)||!["off","false","hide","0","no","n"].includes(o)&&void 0}function y(o){console.log(e.green(o))}function _(o){console.log(e.yellow(o))}function b(o){console.error(e.red(o))}async function h(o,t){console.log(e.gray(i.t("setup.validating",{label:o})));const s=await d(t);return!!s.valid||(b(i.t("setup.invalid_key",{label:o,reason:s.message||s.error||"invalid"})),"network_error"===s.error&&_(i.t("base.network_hint")),!1)}async function x(o,t,s={}){const{oneMillion:d,officialLogin:r,desktopRegistry:c,force:u}=s,g=n[o];try{"claude-desktop"===o&&void 0!==c&&a.setToolSetting("claude-desktop",f,c),"codex"===o&&void 0!==d&&a.setToolSetting("codex",p,d),"claude-desktop"===o&&void 0!==r&&a.setToolSetting("claude-desktop",m,!r),await l.applyPrivateConfig(o,t,a.getModelsForTool(o),{force:u})}catch(e){const o=(e instanceof Error?e.message:String(e)).replace(/\s+/g," ").trim();return b("× "+i.t("setup.apply_failed",{tool:g.displayName,reason:o})),!1}return l.printApplied(o),u&&console.log(e.gray(" "+i.t("config.force_done",{tool:g.displayName}))),"codex"===o&&void 0!==d&&console.log(e.gray(" "+i.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),l.isToolInstalled(o)||console.log(e.yellow(" ! "+i.t("setup.install_hint",{tool:g.displayName,install:g.installCommand}))),!0}export async function setupCommand(e){const d=e.key?.trim(),r=e.claudekey?.trim(),f=e.codexkey?.trim(),m=e.grokkey?.trim(),v=e.desktopkey?.trim(),w=void 0!==e.oneMillion,C=void 0!==e.claudeOfficial;let
|
|
1
|
+
import e from"chalk";import{getAdapter as o}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as s}from"./base.js";import{i18n as i}from"../lib/i18n.js";import{configManager as a}from"../lib/config.js";import{toolManager as l,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as d,fetchModels as r}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as p,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";async function g(e){const o=await r(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),hasGemini:t.some(e=>e.startsWith("gemini")),probed:!0}}function k(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}export function parseOnOff(e){const o=(e??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(o)||!["off","false","hide","0","no","n"].includes(o)&&void 0}function y(o){console.log(e.green(o))}function _(o){console.log(e.yellow(o))}function b(o){console.error(e.red(o))}async function h(o,t){console.log(e.gray(i.t("setup.validating",{label:o})));const s=await d(t);return!!s.valid||(b(i.t("setup.invalid_key",{label:o,reason:s.message||s.error||"invalid"})),"network_error"===s.error&&_(i.t("base.network_hint")),!1)}async function x(o,t,s={}){const{oneMillion:d,officialLogin:r,desktopRegistry:c,force:u}=s,g=n[o];try{"claude-desktop"===o&&void 0!==c&&a.setToolSetting("claude-desktop",f,c),"codex"===o&&void 0!==d&&a.setToolSetting("codex",p,d),"claude-desktop"===o&&void 0!==r&&a.setToolSetting("claude-desktop",m,!r),await l.applyPrivateConfig(o,t,a.getModelsForTool(o),{force:u})}catch(e){const o=(e instanceof Error?e.message:String(e)).replace(/\s+/g," ").trim();return b("× "+i.t("setup.apply_failed",{tool:g.displayName,reason:o})),!1}return l.printApplied(o),u&&console.log(e.gray(" "+i.t("config.force_done",{tool:g.displayName}))),"codex"===o&&void 0!==d&&console.log(e.gray(" "+i.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),l.isToolInstalled(o)||console.log(e.yellow(" ! "+i.t("setup.install_hint",{tool:g.displayName,install:g.installCommand}))),!0}export async function setupCommand(e){const d=e.key?.trim(),r=e.claudekey?.trim(),f=e.codexkey?.trim(),m=e.grokkey?.trim(),v=e.desktopkey?.trim(),w=void 0!==e.oneMillion,C=void 0!==e.claudeOfficial;let G;if(C&&(G=parseOnOff(e.claudeOfficial),void 0===G))return b(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)})),void(process.exitCode=1);const M=void 0!==e.desktopRegistry;let K;if(M&&(K=parseOnOff(e.desktopRegistry),void 0===K))return b(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)})),void(process.exitCode=1);const T=C||M,j=Boolean(d||r||f||m||v),S={oneMillion:e.oneMillion,officialLogin:G,desktopRegistry:K,force:e.force};if(!j&&(w||T)){if(w){const o=a.getApiKeyForTool("codex");if(o)try{const t=!0===e.oneMillion;a.setToolSetting("codex",p,t);const s=await u(o);c(t,s??void 0),y(i.t(t?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(e){b(i.t("setup.apply_failed",{tool:n.codex.displayName,reason:e instanceof Error?e.message:String(e)})),process.exitCode=1}else b(i.t("setup.codex_1m_missing_key")),process.exitCode=1}if(T){const e=a.getApiKeyForTool("claude-desktop");e?await x("claude-desktop",e,{...S,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(b(i.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!j)return b(i.t("setup.usage")),void(process.exitCode=1);await s(d||r||f||m||v);let O=0,A=0;const I=new Set,N=[];r&&N.push({tool:"claude-code",label:"--claudekey",apiKey:r,need:"claude"}),f&&N.push({tool:"codex",label:"--codexkey",apiKey:f,need:"gpt"}),m&&N.push({tool:"grok",label:"--grokkey",apiKey:m,need:"grok"}),v&&N.push({tool:"claude-desktop",label:"--desktopkey",apiKey:v,need:"claude"});for(const e of N){if(!await h(e.label,e.apiKey)){A+=1;continue}const o=await g(e.apiKey);!o.probed||k(o,e.need)?(o.probed||_(i.t("setup.probe_failed",{label:e.label})),a.setToolApiKey(e.tool,e.apiKey),await x(e.tool,e.apiKey,S)?(O+=1,I.add(e.tool)):A+=1):(b(i.t(`setup.key_no_${e.need}`,{label:e.label,tool:n[e.tool].displayName})),A+=1)}if(d){if(!await h("--key",d))return void(process.exitCode=1);a.setApiKey(d);const e=await g(d);if(e.probed||_(i.t("setup.probe_failed",{label:"--key"})),e.probed&&!e.hasClaude&&!e.hasGpt&&!e.hasGrok)return b(i.t("setup.key_no_family")),void(process.exitCode=1);const o=[{tool:"claude-code",capable:e.hasClaude,skipMsg:i.t("setup.skip_no_claude")},{tool:"codex",capable:e.hasGpt,skipMsg:i.t("setup.skip_no_gpt")},{tool:"grok",capable:e.hasGrok,skipMsg:i.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:e.hasClaude&&l.isToolInstalled("claude-desktop"),skipMsg:i.t("setup.skip_desktop_not_installed"),quiet:!e.hasClaude},{tool:"agy",capable:e.hasGemini&&l.isToolInstalled("agy"),skipMsg:i.t("setup.skip_no_gemini"),quiet:!l.isToolInstalled("agy")}];for(const e of o)I.has(e.tool)||(e.capable?await x(e.tool,d,S)?(O+=1,I.add(e.tool)):A+=1:e.quiet||_(e.skipMsg))}if(O>0){const e=[...I].filter(e=>!o(e)?.isInstalled).map(e=>n[e]?.command).filter(Boolean).join(" / "),t=i.t("setup.done",{count:String(O)});y("\n"+(e?`${t}${i.t("setup.done_commands",{commands:e})}`:t))}A>0&&b(i.t("setup.failed_summary",{count:String(A)})),await t([...I]),(A>0||0===O)&&(process.exitCode=1)}
|
|
@@ -16,6 +16,8 @@ export declare function getShellRcFilePath(): string | null;
|
|
|
16
16
|
export declare function cleanupShellRcEnvVars(): boolean;
|
|
17
17
|
/** 测试注入假的 PowerShell。 */
|
|
18
18
|
export declare function setPowerShellRunnerForTests(fake: (script: string) => string): void;
|
|
19
|
+
/** 经可注入的 PowerShell 执行一段脚本(测试里由 `setPowerShellRunnerForTests` 替换)。 */
|
|
20
|
+
export declare function runPowerShell(script: string): string;
|
|
19
21
|
/**
|
|
20
22
|
* Windows 上这些变量的持久来源是「用户环境变量」「系统环境变量」和 PowerShell 配置文件里的
|
|
21
23
|
* `$env:NAME = ...`。用户级用 .NET 接口删除(会广播变更,新开的终端立即生效,不需要管理员);
|
package/dist/lib/env-cleanup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as e}from"child_process";import{existsSync as n,readFileSync as r,writeFileSync as o}from"fs";import{join as t}from"path";import{logger as i}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=s();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return t(e,".bashrc");case"zsh":return t(e,".zshrc");case"fish":return t(e,".config","fish","config.fish");default:return t(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const e=getShellRcFilePath();if(!e||!n(e))return!1;let t=r(e,"utf-8");const s=t,l=[...ANTHROPIC_ENV_VARS.map(e=>new RegExp(String.raw`^\s*export\s+${e}=.*$`,"gm")),/^\s*#\s*Claude Code environment variables\s*$/gm];for(const e of l)t=t.replace(e,"");if(t!==s)return o(e,t,"utf-8"),i.info(`Cleaned up ANTHROPIC_* environment variables from ${e}`),!0}catch(e){i.warn("Failed to cleanup shell environment variables:",e),i.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}let l=n=>e("powershell.exe",["-NoProfile","-NonInteractive","-Command",n],{encoding:"utf-8",windowsHide:!0,timeout:2e4});export function setPowerShellRunnerForTests(e){l=e}export function cleanupWindowsEnvVars(e){const c=[];if("win32"!==process.platform||0===e.length)return{machineLeft:c};try{const n=e.map(e=>`'${e}'`).join(","),r=l(`foreach($n in @(${n})){if($null -ne [Environment]::GetEnvironmentVariable($n,'User')){[Environment]::SetEnvironmentVariable($n,$null,'User');"user:$n"};if($null -ne [Environment]::GetEnvironmentVariable($n,'Machine')){try{[Environment]::SetEnvironmentVariable($n,$null,'Machine');"machine-removed:$n"}catch{"machine:$n"}}}`);for(const e of r.split(/\r?\n/)){const n=e.trim().match(/^machine:(\w+)$/);n&&c.push(n[1])}i.info(`Windows env cleanup: ${r.replace(/\s+/g," ").trim()}`)}catch(e){i.logError("envCleanup.cleanupWindowsEnvVars",e)}for(const l of function(){const e=s(),n=[];for(const r of[t(e,"Documents"),t(e,"OneDrive","Documents"),t(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(t(r,e,"Microsoft.PowerShell_profile.ps1"),t(r,e,"profile.ps1"));return n}())try{if(!n(l))continue;const t=r(l,"utf-8");let s=t;for(const n of e)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${n}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==t&&(o(l,s,"utf-8"),i.info(`Removed ANTHROPIC_* assignments from ${l}`))}catch(e){i.logError("envCleanup.powerShellProfile",e)}return{machineLeft:c}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];cleanupShellRcEnvVars(),c=cleanupWindowsEnvVars(e).machineLeft;for(const n of e)delete process.env[n];return[...e]}let c=[];export function machineEnvVarsLeft(){return c}
|
|
1
|
+
import{execFileSync as e}from"child_process";import{existsSync as n,readFileSync as r,writeFileSync as o}from"fs";import{join as t}from"path";import{logger as i}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=s();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return t(e,".bashrc");case"zsh":return t(e,".zshrc");case"fish":return t(e,".config","fish","config.fish");default:return t(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const e=getShellRcFilePath();if(!e||!n(e))return!1;let t=r(e,"utf-8");const s=t,l=[...ANTHROPIC_ENV_VARS.map(e=>new RegExp(String.raw`^\s*export\s+${e}=.*$`,"gm")),/^\s*#\s*Claude Code environment variables\s*$/gm];for(const e of l)t=t.replace(e,"");if(t!==s)return o(e,t,"utf-8"),i.info(`Cleaned up ANTHROPIC_* environment variables from ${e}`),!0}catch(e){i.warn("Failed to cleanup shell environment variables:",e),i.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}let l=n=>e("powershell.exe",["-NoProfile","-NonInteractive","-Command",n],{encoding:"utf-8",windowsHide:!0,timeout:2e4});export function setPowerShellRunnerForTests(e){l=e}export function runPowerShell(e){return l(e)}export function cleanupWindowsEnvVars(e){const c=[];if("win32"!==process.platform||0===e.length)return{machineLeft:c};try{const n=e.map(e=>`'${e}'`).join(","),r=l(`foreach($n in @(${n})){if($null -ne [Environment]::GetEnvironmentVariable($n,'User')){[Environment]::SetEnvironmentVariable($n,$null,'User');"user:$n"};if($null -ne [Environment]::GetEnvironmentVariable($n,'Machine')){try{[Environment]::SetEnvironmentVariable($n,$null,'Machine');"machine-removed:$n"}catch{"machine:$n"}}}`);for(const e of r.split(/\r?\n/)){const n=e.trim().match(/^machine:(\w+)$/);n&&c.push(n[1])}i.info(`Windows env cleanup: ${r.replace(/\s+/g," ").trim()}`)}catch(e){i.logError("envCleanup.cleanupWindowsEnvVars",e)}for(const l of function(){const e=s(),n=[];for(const r of[t(e,"Documents"),t(e,"OneDrive","Documents"),t(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(t(r,e,"Microsoft.PowerShell_profile.ps1"),t(r,e,"profile.ps1"));return n}())try{if(!n(l))continue;const t=r(l,"utf-8");let s=t;for(const n of e)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${n}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==t&&(o(l,s,"utf-8"),i.info(`Removed ANTHROPIC_* assignments from ${l}`))}catch(e){i.logError("envCleanup.powerShellProfile",e)}return{machineLeft:c}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];cleanupShellRcEnvVars(),c=cleanupWindowsEnvVars(e).machineLeft;for(const n of e)delete process.env[n];return[...e]}let c=[];export function machineEnvVarsLeft(){return c}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PersistentEnvResult {
|
|
2
|
+
/** rc 文件里加了加载行(新开终端才生效);Windows 为空。 */
|
|
3
|
+
rcFiles: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* 写入(覆盖)env 文件并确保各 rc / Windows 用户环境变量指向这些值。
|
|
7
|
+
* 同时更新本进程的 process.env,让 vibecli 随后启动的子进程立即可用。
|
|
8
|
+
*/
|
|
9
|
+
export declare function writePersistentEnv(id: string, envFile: string, vars: Record<string, string>): PersistentEnvResult;
|
|
10
|
+
/** 删掉 env 文件、rc 里我们加的那一行,以及 Windows 用户环境变量里我们写的值。 */
|
|
11
|
+
export declare function removePersistentEnv(id: string, envFile: string, names: readonly string[]): void;
|
|
12
|
+
/** 读回 env 文件里的变量;文件不存在或没有内容时为空对象。 */
|
|
13
|
+
export declare function readPersistentEnvFile(envFile: string): Record<string, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{chmodSync as n,existsSync as t,readFileSync as e,realpathSync as o,unlinkSync as r}from"fs";import{join as i}from"path";import{logger as s}from"../utils/logger.js";import{getShellRcFilePath as c,runPowerShell as f}from"./env-cleanup.js";import{atomicWriteFile as l,backupBeforeWrite as u}from"./tools/backup.js";import{toolHome as p}from"./tools/types.js";const a=n=>`# vibecli:${n}`;function m(){const n=p(),e=new Set,o=c();o&&e.add(o);for(const o of[".zshrc",".bashrc"]){const r=i(n,o);t(r)&&e.add(r)}return[...e]}function $(n,t,e){const o=`"${function(n){const t=p();return n.startsWith(t+"/")?`$HOME/${n.slice(t.length+1)}`:n}(t)}"`;return n.endsWith(".fish")?`test -f ${o}; and source ${o} ${a(e)}`:`[ -f ${o} ] && . ${o} ${a(e)}`}function v(n,e){const r=t(n)?o(n):n;u(r),l(r,e)}function E(n,t){return n.split("\n").filter(n=>!n.trimEnd().endsWith(a(t))).join("\n")}function d(n,t){if(/['\r\n]/.test(t))throw new Error(`${n} contains a quote or newline and cannot be written to a shell env file`)}export function writePersistentEnv(o,r,i){for(const[n,t]of Object.entries(i))d(n,t);const s=Object.entries(i).map(([n,t])=>`export ${n}='${t}'`).join("\n");u(r),l(r,`# Written by vibecli. Loaded from your shell profile.\n${s}\n`,384),n(r,384);for(const[n,t]of Object.entries(i))process.env[n]=t;if("win32"===process.platform){const n=Object.entries(i).map(([n,t])=>`[Environment]::SetEnvironmentVariable('${n}','${t}','User')`).join(";");return f(n),{rcFiles:[]}}const c=[];for(const n of m()){const i=t(n)?e(n,"utf-8"):"",s=$(n,r,o);if(i.split("\n").some(n=>n.trimEnd()===s)){c.push(n);continue}const f=E(i,o).replace(/\n*$/,"");v(n,`${f?f+"\n\n":""}${s}\n`),c.push(n)}return{rcFiles:c}}export function removePersistentEnv(n,o,i){const c=readPersistentEnvFile(o);if(t(o)&&(u(o),r(o)),"win32"===process.platform){const n=i.filter(n=>void 0!==c[n]).map(n=>`if([Environment]::GetEnvironmentVariable('${n}','User') -eq '${c[n]}'){[Environment]::SetEnvironmentVariable('${n}',$null,'User')}`).join(";");if(n)try{f(n)}catch(n){s.logError("persistentEnv.remove",n)}return}for(const o of m()){if(!t(o))continue;const r=e(o,"utf-8"),i=E(r,n);i!==r&&v(o,i)}}export function readPersistentEnvFile(n){const o={};if(!t(n))return o;for(const t of e(n,"utf-8").split("\n")){const n=t.match(/^export ([A-Z_][A-Z0-9_]*)='([^']*)'$/);n&&(o[n[1]]=n[2])}return o}
|
package/dist/lib/tool-manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as i}from"../utils/logger.js";import{configManager as l}from"./config.js";import{getAdapter as s,listAdapters as a,TOOL_ADAPTERS as c}from"./tools/registry.js";import{backupBeforeWrite as d,listBackups as p,restoreBackup as u}from"./tools/backup.js";import{existsSync as f,rmSync as m}from"fs";import{stringWidth as g}from"../utils/string-width.js";import{resolveModelCatalog as h}from"./model-catalog.js";import{compareVersions as w,getToolMinVersion as P}from"./model-registry.js";import{findInstalls as y,forgetInstalls as T,installLabel as C,
|
|
1
|
+
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as i}from"../utils/logger.js";import{configManager as l}from"./config.js";import{getAdapter as s,listAdapters as a,TOOL_ADAPTERS as c}from"./tools/registry.js";import{backupBeforeWrite as d,listBackups as p,restoreBackup as u}from"./tools/backup.js";import{existsSync as f,rmSync as m}from"fs";import{stringWidth as g}from"../utils/string-width.js";import{resolveModelCatalog as h}from"./model-catalog.js";import{compareVersions as w,getToolMinVersion as P}from"./model-registry.js";import{findInstalls as y,forgetInstalls as T,installLabel as C,mirrorInstallCommand as k}from"./tools/tool-installs.js";export{w as compareVersions};function $(o){const t=c[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(c).map(o=>[o,$(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 e=s(t);if(e?.isInstalled)try{return e.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 i=SUPPORTED_TOOLS[t];if(!i)throw new Error(`Unknown tool: ${t}`);const l=s(t)?.installSpec,a=l?k(l):i.installCommand;console.log(r.gray("$ ")+r.white(a));try{return o(a,{stdio:"inherit"}),T(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!a.startsWith("npm "))throw new Error(`Failed to install ${i.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:a}):n.t("install.permission_unix",{command:a}))))}const{action:c}=await e.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"===c)throw new Error(n.t("install.user_cancelled"));if(T(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:i.displayName}))),new Error(`${i.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:i.displayName})))}getToolConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return i.warn(`Failed to read config for ${o}:`,t),i.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=s(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=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)f(o)&&(d(o),m(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=s(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:l.getBaseUrl(),models:n,settings:l.getToolSettings(o),...e?{catalog:e}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=s(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await h(t):null;e.force?this.loadPrivateConfig(o,t,n,i??void 0,{force:!0}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=s(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){i.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`vibecli upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const l=t.installSpec?y(t.installSpec):[];return l.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(l.length),active:C(l[0]),others:l.slice(1).map(C).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))i.record(`${n}: ${o.text}`);const l=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),s=" ".repeat(Math.max(1,t-g(n)));console.log(r.green("√ "+n)+(l?s+l:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=s(o);if(!n)return null;if(n.installSpec)return y(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return i.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"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=P(o);if(!t)return null;const n=this.installedVersion(o);return n&&w(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);t.unloadPrivateConfig()}async clearPinnedModels(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(l.setToolModel(o,null),!t.clearPinnedModels)return[];const n=l.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await h(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(s(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=s(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=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:p(o)}))}restorePrivateConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:u(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return a().filter(o=>!o.hidden).map(o=>$(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();
|
package/dist/lib/tool-upgrade.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as
|
|
1
|
+
import{spawnSync as r}from"child_process";import{rmSync as e}from"fs";import{join as o}from"path";import t from"chalk";import n from"inquirer";import{i18n as i}from"./i18n.js";import{logger as s}from"../utils/logger.js";import{compareVersions as a,getToolMinVersion as l}from"./model-registry.js";import{getAdapter as p}from"./tools/registry.js";import{findInstalls as c,forgetInstalls as u,installLabel as m,mirrorInstallCommand as g,npmUninstallCommand as d}from"./tools/tool-installs.js";import{toolHome as f}from"./tools/types.js";import{isNonInteractive as w,shouldAutoConfirm as h}from"./runtime-options.js";let v=(e,o)=>{console.log(t.gray("$ ")+[e,...o].join(" "));const n="win32"!==process.platform||/\.exe$/i.test(e)?r(e,o,{stdio:"inherit"}):r([e,...o].map(r=>/\s/.test(r)?`"${r}"`:r).join(" "),{stdio:"inherit",shell:!0});return n.error&&s.logError(`upgrade: ${e}`,n.error),0===n.status};export function setUpgradeRunnerForTests(r){v=r}function y(r){if(r.mirrorScript)return"win32"===process.platform?v("powershell.exe",["-NoProfile","-ExecutionPolicy","Bypass","-Command",`irm ${r.mirrorScript.ps1} | iex`]):v("sh",["-c",g(r)]);const[e,...o]=g(r).split(" "),n=v(e,o);return n||"win32"===process.platform||console.log(t.yellow(" ! "+i.t("upgrade.npm_permission",{command:g(r)}))),n}function _(r,t){switch(t.kind){case"npm":r.npmPackage&&v("npm",["uninstall","-g",r.npmPackage]);break;case"brew":r.brew&&v("brew",["uninstall",r.brew]);break;case"native":try{e(t.path,{force:!0});for(const t of r.native?.dataDirs??[])e(o(f(),...t),{recursive:!0,force:!0})}catch(r){s.logError("upgrade: remove native copy",r)}break;default:return!1}return u(),!c(r).some(r=>r.path===t.path)}function b(r,e){switch(e.kind){case"npm":return d(r);case"brew":return`brew uninstall ${r.brew}`;case"native":return i.t("upgrade.delete_paths",{paths:[e.path,...(r.native?.dataDirs??[]).map(r=>o(f(),...r))].join("、")});default:return i.t("upgrade.delete_paths",{paths:e.path})}}export async function upgradeTool(r){const e=p(r),o=e?.installSpec;if(!e||!o)throw new Error(i.t("upgrade.unsupported",{tool:r}));const g=e.displayName;u();const d=c(o);if(console.log(t.bold(`\n${g}`)),0===d.length)console.log(i.t("upgrade.not_installed_installing",{tool:g})),y(o);else{const r=d[0];console.log(t.gray(" "+i.t("upgrade.current",{copy:m(r)})));const e=function(r,e){switch(e.kind){case"native":return v(e.path,r.native?.updateArgs??["update"]);case"npm":return y(r);case"brew":return!!r.brew&&v("brew",["upgrade",r.brew]);default:return!1}}(o,r);e||"other"!==r.kind?e||"npm"===r.kind||"native"===r.kind&&await async function(r){const e=r.native?.mirrorUpdate;if(!e)return!1;console.log(t.yellow(" ! "+i.t("upgrade.native_mirror_trying")));try{const{version:r,manifestVerified:o}=await e();return console.log(t.green(" √ "+i.t(o?"upgrade.native_mirror_done_verified":"upgrade.native_mirror_done",{version:r}))),!0}catch(r){return s.logError("upgrade: native mirror",r),console.log(t.yellow(" ! "+i.t("upgrade.native_mirror_failed",{reason:r instanceof Error?r.message:String(r)}))),!1}}(o)||(console.log(t.yellow(" ! "+i.t("upgrade.fallback_mirror"))),y(o)):console.log(t.yellow(" ! "+i.t("upgrade.unknown_install",{path:r.path})))}u(),await async function(r,e){const o=c(r);if(o.length<2)return;const s=function(r){return r.reduce((r,e)=>e.version&&(!r.version||a(e.version,r.version)>0)?e:r)}(o),l=o.filter(r=>r!==s);console.log(t.yellow(" ! "+i.t("upgrade.duplicates",{tool:e,keep:m(s),others:l.map(m).join("、")})));let p=h();p||w()||!process.stdin.isTTY||(p=(await n.prompt([{type:"confirm",name:"remove",message:i.t("upgrade.confirm_remove"),default:!0}])).remove);for(const e of l)p&&_(r,e)?console.log(t.green(" √ "+i.t("upgrade.removed",{copy:m(e)}))):console.log(t.yellow(" ! "+i.t("upgrade.remove_by_hand",{how:b(r,e)})))}(o,g),u();const f=c(o)[0];if(!f)return console.log(t.red(" × "+i.t("upgrade.still_missing",{tool:g}))),!1;const k=l(r);if(k&&f.version&&a(f.version,k)<0){console.log(t.yellow(" ! "+i.t("upgrade.still_old",{copy:m(f),min:k})));for(const r of e.upgradeHints?.(k)??[])console.log(t.yellow(" ! "+r));return!1}return console.log(t.green(" √ "+i.t("upgrade.done",{copy:m(f)}))),!0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as t,readFileSync as r}from"fs";import{join as i}from"path";import{i18n as e}from"../i18n.js";import{logger as n}from"../../utils/logger.js";import{readPersistentEnvFile as o,removePersistentEnv as a,writePersistentEnv as s}from"../persistent-env.js";import{backupBeforeWrite as l,atomicWriteFile as p}from"./backup.js";import{mirrorInstallCommand as c}from"./tool-installs.js";import{toolHome as g}from"./types.js";const m="GEMINI_API_KEY",d="GOOGLE_GEMINI_BASE_URL",f="gemini",y=()=>i(g(),".gemini","antigravity-cli"),u=()=>i(y(),"settings.json"),v=()=>i(y(),"vibeapi.env"),b="https://cnb.cool/vibeapi/agy/-/releases/latest/download",h={command:"agy",native:{binDir:"win32"===process.platform?["AppData","Local","agy","bin"]:[".local","bin"],updateArgs:["update"],dataDirs:[]},mirrorScript:{sh:`${b}/install.sh`,ps1:`${b}/install.ps1`}};function j(){if(!t(u()))return{};const i=r(u(),"utf-8");if(!i.trim())return{};try{const t=JSON.parse(i);if(!(e=t)||"object"!=typeof e||Array.isArray(e))throw new Error("settings.json root must be an object");return t}catch(t){throw new Error(`Existing ~/.gemini/antigravity-cli/settings.json cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}var e}function P(t){l(u()),p(u(),JSON.stringify(t,null,2)+"\n")}let E=null;export const antigravityAdapter={name:"agy",displayName:"Antigravity CLI",command:"agy",installCommand:c(h),installSpec:h,configPath:u(),loadPrivateConfig(t){const r=j();var i;E=s("agy",v(),{[m]:t.apiKey,[d]:(i=t.baseUrl,(i||"").replace(/\/+$/,"").replace(/\/v1(beta)?$/,""))}).rcFiles,r.modelProvider!==f&&(r.modelProvider=f,P(r))},unloadPrivateConfig(){try{const t=j();t.modelProvider===f&&(delete t.modelProvider,P(t))}catch(t){n.logError("antigravityAdapter.unloadPrivateConfig",t)}a("agy",v(),[m,d])},detectCurrentConfig(){try{if(j().modelProvider!==f)return{apiKey:null}}catch{return{apiKey:null}}const t=o(v())[m];return{apiKey:t&&t.trim()?t:null}},getConfig(){try{return j()}catch(t){return n.logError("antigravityAdapter.getConfig",t),null}},applyNotes:()=>null===E?[]:0===E.length?[{kind:"action",text:e.t("tools.agy.reopen_terminal_windows")}]:[{kind:"action",text:e.t("tools.agy.reopen_terminal",{rc:E.join(", ")})}],backupPaths:()=>[u(),v()],forceResetPaths:()=>[v()]};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* leaves the original intact instead of a half-written config. Cleans up the
|
|
5
5
|
* temp file on failure and rethrows.
|
|
6
6
|
*/
|
|
7
|
-
export declare function atomicWriteFile(filePath: string, content: string): void;
|
|
7
|
+
export declare function atomicWriteFile(filePath: string, content: string, mode?: number): void;
|
|
8
8
|
/** How many timestamped backups to keep per file before the oldest are pruned. */
|
|
9
9
|
export declare const MAX_TOOL_BACKUPS = 10;
|
|
10
10
|
/**
|
package/dist/lib/tools/backup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as t,copyFileSync as r,readdirSync as e,statSync as o,unlinkSync as s,writeFileSync as c,renameSync as n,mkdirSync as a}from"fs";import{dirname as i,basename as u,join as m}from"path";import{logger as p}from"../../utils/logger.js";export function atomicWriteFile(r,e){const
|
|
1
|
+
import{existsSync as t,copyFileSync as r,readdirSync as e,statSync as o,unlinkSync as s,writeFileSync as c,renameSync as n,mkdirSync as a}from"fs";import{dirname as i,basename as u,join as m}from"path";import{logger as p}from"../../utils/logger.js";export function atomicWriteFile(r,e,o){const u=i(r);t(u)||a(u,{recursive:!0});const m=`${r}.tmp-${process.pid}-${Date.now()}`;try{c(m,e,void 0===o?"utf-8":{encoding:"utf-8",mode:o}),n(m,r)}catch(r){try{t(m)&&s(m)}catch{}throw r}}export const MAX_TOOL_BACKUPS=10;const f=".bak-";function h(r){const e=`${r}${f}${(new Date).toISOString().replace(/[:.]/g,"-")}`;let o=e,s=1;for(;t(o);)o=`${e}-${s++}`;return o}export function backupBeforeWrite(e,o=10){try{if(!t(e))return;r(e,h(e)),b(e,o)}catch(t){p.logError("backupBeforeWrite",t)}}function d(t){const r=t.match(/Z-(\d+)$/);return r?Number(r[1]):0}function l(t){const r=t.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z(?:-\d+)?$/);if(!r)return 0;const[,e,o,s,c,n,a,i]=r;return Date.UTC(Number(e),Number(o)-1,Number(s),Number(c),Number(n),Number(a),Number(i))}export function listBackups(t){const r=i(t),s=u(t)+f;try{return e(r).filter(t=>t.startsWith(s)).map(t=>{const e=m(r,t);return{path:e,name:t,mtimeMs:o(e).mtimeMs,seq:d(t),timestampMs:l(t)}}).sort((t,r)=>r.timestampMs-t.timestampMs||r.seq-t.seq||r.mtimeMs-t.mtimeMs)}catch{return[]}}export function restoreBackup(e,o){const s=o?listBackups(e).find(t=>t.path===o||t.name===o)?.path:listBackups(e)[0]?.path;if(!s||!t(s))return{restored:!1,reason:"no_backup"};let c;if(t(e)){const t=h(e);try{r(e,t),c=u(t)}catch(t){p.logError("restoreBackup.snapshot",t)}}return r(s,e),b(e,10),{restored:!0,from:u(s),snapshot:c}}function b(t,r){for(const e of listBackups(t).slice(Math.max(0,r)))try{s(e.path)}catch(t){p.logError("backupBeforeWrite.rotate",t)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{claudeCodeAdapter as o}from"./claude-code.js";import{opencodeAdapter as r}from"./opencode.js";import{codexAdapter as t}from"./codex.js";import{openclawAdapter as
|
|
1
|
+
import{claudeCodeAdapter as o}from"./claude-code.js";import{opencodeAdapter as r}from"./opencode.js";import{codexAdapter as t}from"./codex.js";import{openclawAdapter as m}from"./openclaw.js";import{hermesAdapter as e}from"./hermes.js";import{atomcodeAdapter as p}from"./atomcode.js";import{grokAdapter as s}from"./grok.js";import{claudeDesktopAdapter as i}from"./claude-desktop.js";import{antigravityAdapter as n}from"./antigravity.js";const c=[o,r,t,m,e,p,s,i,n];export const TOOL_ADAPTERS=Object.fromEntries(c.map(o=>[o.name,o]));export function getAdapter(o){return TOOL_ADAPTERS[o]}export function listAdapters(){return[...c]}
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
export interface ToolInstallSpec {
|
|
9
9
|
/** Executable name without extension (`claude`). */
|
|
10
10
|
command: string;
|
|
11
|
-
/** npm package of the global install (`@anthropic-ai/claude-code`). */
|
|
12
|
-
npmPackage
|
|
11
|
+
/** npm package of the global install (`@anthropic-ai/claude-code`); absent for tools not on npm. */
|
|
12
|
+
npmPackage?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Install scripts on our CNB download mirror, for tools not on npm (agy): they take the
|
|
15
|
+
* npm mirror's place when installing and when the vendor updater fails.
|
|
16
|
+
*/
|
|
17
|
+
mirrorScript?: {
|
|
18
|
+
sh: string;
|
|
19
|
+
ps1: string;
|
|
20
|
+
};
|
|
13
21
|
/** The vendor's self-updating install, when there is one. */
|
|
14
22
|
native?: {
|
|
15
23
|
/** Directory under the home directory holding the launcher (`.local/bin`). */
|
|
@@ -38,7 +46,8 @@ export interface ToolInstall {
|
|
|
38
46
|
}
|
|
39
47
|
/** npmmirror carries the same packages (including the per-platform native binaries) and is reachable from mainland China. */
|
|
40
48
|
export declare const NPM_MIRROR = "https://registry.npmmirror.com";
|
|
41
|
-
|
|
49
|
+
/** The China-reachable install command: the CNB mirror's script, or npm from npmmirror. */
|
|
50
|
+
export declare function mirrorInstallCommand(spec: ToolInstallSpec): string;
|
|
42
51
|
export declare function npmUninstallCommand(spec: ToolInstallSpec): string;
|
|
43
52
|
/** `原生安装 2.1.295 (C:\\Users\\me\\.local\\bin\\claude.exe)` */
|
|
44
53
|
export declare function installLabel(install: ToolInstall): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as t}from"child_process";import{existsSync as
|
|
1
|
+
import{spawnSync as t}from"child_process";import{existsSync as r,realpathSync as n,statSync as o}from"fs";import{delimiter as e,dirname as i,isAbsolute as s,join as c}from"path";import{i18n as m}from"../i18n.js";import{toolHome as a}from"./types.js";export const NPM_MIRROR="https://registry.npmmirror.com";export function mirrorInstallCommand(t){return t.mirrorScript?"win32"===process.platform?`powershell -NoProfile -ExecutionPolicy Bypass -Command "irm ${t.mirrorScript.ps1} | iex"`:`curl -fsSL ${t.mirrorScript.sh} | sh`:`npm install -g ${t.npmPackage}@latest --registry=${NPM_MIRROR}`}export function npmUninstallCommand(t){return`npm uninstall -g ${t.npmPackage}`}export function installLabel(t){return`${m.t(`upgrade.kind.${t.kind}`)} ${t.version??"?"} (${t.path})`}let p=r=>{const n={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]};return`${(/\.cmd$/i.test(r)?t(`"${r}" --version`,{...n,shell:!0}):t(r,["--version"],n)).stdout??""}`};const l=new Map;export function setVersionRunnerForTests(t){p=t,l.clear()}export function forgetInstalls(){l.clear()}function u(t){try{return o(t).isFile()}catch{return!1}}function f(t,o){if(t.native&&(e=i(o),s=c(a(),...t.native.binDir),"win32"===process.platform?e.toLowerCase()===s.toLowerCase():e===s))return"native";var e,s;const m=t.npmPackage?c("node_modules",...t.npmPackage.split("/")):null;if(m&&r(c(i(o),m)))return"npm";let p=o;try{p=n(o)}catch{return"other"}return m&&p.includes(m)?"npm":/[\\/](Cellar|Caskroom)[\\/]/.test(p)?"brew":"other"}export function findInstalls(t){const r=l.get(t.command);if(r)return r;const o="win32"===process.platform?[`${t.command}.exe`,`${t.command}.cmd`]:[t.command],i=new Set,m=[];for(const r of(process.env.PATH??"").split(e))if(r&&s(r))for(const e of o){const o=c(r,e);if(!u(o))continue;let s=o;try{s=n(o)}catch{}const a="win32"===process.platform?s.toLowerCase():s;if(i.has(a))continue;i.add(a);const l=p(o).match(/(\d+)\.(\d+)\.(\d+)/);m.push({path:o,kind:f(t,o),version:l?l[0]:null})}return l.set(t.command,m),m}
|
package/dist/locales/en_US.json
CHANGED
|
@@ -357,6 +357,7 @@
|
|
|
357
357
|
"skip_no_claude": "This key has no Claude model group; skipped Claude Code",
|
|
358
358
|
"skip_no_gpt": "This key has no GPT model group; skipped Codex",
|
|
359
359
|
"skip_no_grok": "This key has no Grok model group; skipped Grok Build",
|
|
360
|
+
"skip_no_gemini": "This key has no Gemini model group; skipped Antigravity CLI",
|
|
360
361
|
"apply_failed": "Failed to write {{tool}} config: {{reason}}",
|
|
361
362
|
"install_hint": "{{tool}} not found; install it with {{install}}",
|
|
362
363
|
"done": "Done: {{count}} tool(s) configured. ",
|
|
@@ -376,6 +377,10 @@
|
|
|
376
377
|
},
|
|
377
378
|
"tools": {
|
|
378
379
|
"version_outdated": "version {{current}} is too old (needs {{min}} or later); upgrade with {{upgrade}}",
|
|
380
|
+
"agy": {
|
|
381
|
+
"reopen_terminal": "Key and address were added to {{rc}}; open a new terminal before running agy",
|
|
382
|
+
"reopen_terminal_windows": "Key and address were saved as user environment variables; reopen the terminal before running agy"
|
|
383
|
+
},
|
|
379
384
|
"codex": {
|
|
380
385
|
"catalog_written": "{{count}} models in the menu ({{breakdown}}); reopen the Codex desktop app to see them",
|
|
381
386
|
"catalog_skipped": "Couldn't read Codex's built-in model list (not installed, or older than 0.122), so the menu has GPT models only; install or upgrade Codex and run this again"
|
|
@@ -426,8 +431,8 @@
|
|
|
426
431
|
"supported": "Supported tools: {{tools}}",
|
|
427
432
|
"nothing_installed": "None of {{tools}} is installed",
|
|
428
433
|
"current": "Current: {{copy}}",
|
|
429
|
-
"not_installed_installing": "{{tool}} not found; installing from the
|
|
430
|
-
"fallback_mirror": "The official upgrade failed; installing from the
|
|
434
|
+
"not_installed_installing": "{{tool}} not found; installing from the China mirror",
|
|
435
|
+
"fallback_mirror": "The official upgrade failed; installing from the China mirror instead",
|
|
431
436
|
"unknown_install": "Unknown install source ({{path}}); upgrade it the way it was installed",
|
|
432
437
|
"npm_permission": "npm cannot write the global directory: use sudo {{command}}, or run npm config set prefix ~/.npm-global, add ~/.npm-global/bin to PATH and retry",
|
|
433
438
|
"duplicates": "Several copies of {{tool}}: keeping {{keep}}; extra: {{others}}",
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -357,6 +357,7 @@
|
|
|
357
357
|
"skip_no_claude": "该 Key 未开通 Claude 模型分组,已跳过 Claude Code",
|
|
358
358
|
"skip_no_gpt": "该 Key 未开通 GPT 模型分组,已跳过 Codex",
|
|
359
359
|
"skip_no_grok": "该 Key 未开通 Grok 模型分组,已跳过 Grok Build",
|
|
360
|
+
"skip_no_gemini": "该 Key 未开通 Gemini 模型分组,已跳过 Antigravity CLI",
|
|
360
361
|
"apply_failed": "{{tool}} 配置写入失败: {{reason}}",
|
|
361
362
|
"install_hint": "没检测到 {{tool}},运行 {{install}} 安装",
|
|
362
363
|
"done": "完成:已配置 {{count}} 个工具。",
|
|
@@ -376,6 +377,10 @@
|
|
|
376
377
|
},
|
|
377
378
|
"tools": {
|
|
378
379
|
"version_outdated": "版本 {{current}} 过旧,需要 {{min}} 及以上,运行 {{upgrade}} 升级",
|
|
380
|
+
"agy": {
|
|
381
|
+
"reopen_terminal": "Key 与地址已写入 {{rc}},新开一个终端再运行 agy",
|
|
382
|
+
"reopen_terminal_windows": "Key 与地址已写入用户环境变量,重新打开终端再运行 agy"
|
|
383
|
+
},
|
|
379
384
|
"codex": {
|
|
380
385
|
"catalog_written": "模型菜单 {{count}} 个({{breakdown}}),Codex 桌面版重开后生效",
|
|
381
386
|
"catalog_skipped": "没读到 Codex 自带的模型列表(未安装或版本低于 0.122),模型菜单只有 GPT;安装或升级 Codex 后再运行一次"
|
|
@@ -426,8 +431,8 @@
|
|
|
426
431
|
"supported": "支持的工具:{{tools}}",
|
|
427
432
|
"nothing_installed": "没有找到已安装的 {{tools}}",
|
|
428
433
|
"current": "当前:{{copy}}",
|
|
429
|
-
"not_installed_installing": "没有找到 {{tool}}
|
|
430
|
-
"fallback_mirror": "
|
|
434
|
+
"not_installed_installing": "没有找到 {{tool}},用国内镜像安装",
|
|
435
|
+
"fallback_mirror": "官方渠道升级失败,改用国内镜像安装",
|
|
431
436
|
"unknown_install": "不认识这份安装的来源({{path}}),没法自动升级,请按当初的安装方式升级",
|
|
432
437
|
"npm_permission": "npm 没有权限写全局目录:可以用 sudo {{command}},或运行 npm config set prefix ~/.npm-global 并把 ~/.npm-global/bin 加进 PATH 后重试",
|
|
433
438
|
"duplicates": "本机有多份 {{tool}},保留 {{keep}},多余的是 {{others}}",
|
package/dist/models.json
CHANGED
package/models.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.81",
|
|
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",
|