@vibeapi/api-helper 0.0.89 → 0.0.91

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.
@@ -14,14 +14,10 @@ export declare function getShellRcFilePath(): string | null;
14
14
  * 返回 rc 文件是否被修改。
15
15
  */
16
16
  export declare function cleanupShellRcEnvVars(): boolean;
17
- /** 测试注入假的 PowerShell。 */
18
- export declare function setPowerShellRunnerForTests(fake: (script: string) => string): void;
19
- /** 经可注入的 PowerShell 执行一段脚本(测试里由 `setPowerShellRunnerForTests` 替换)。 */
20
- export declare function runPowerShell(script: string): string;
21
17
  /**
22
18
  * Windows 上这些变量的持久来源是「用户环境变量」「系统环境变量」和 PowerShell 配置文件里的
23
- * `$env:NAME = ...`。用户级用 .NET 接口删除(会广播变更,新开的终端立即生效,不需要管理员);
24
- * 系统级需要管理员,删不掉的名字返回给调用方提示用户。
19
+ * `$env:NAME = ...`。两级都用 reg.exe 删除(见 windows-env.ts,不等广播,避免超时);用户级不需要管理员,
20
+ * 系统级没有管理员权限时删不掉,返回给调用方提示用户。
25
21
  */
26
22
  export declare function cleanupWindowsEnvVars(names: readonly string[]): {
27
23
  machineLeft: string[];
@@ -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 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}
1
+ import{existsSync as e,readFileSync as n,writeFileSync as r}from"fs";import{join as o}from"path";import{logger as t}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";import{broadcastEnvChange as c,deleteWindowsEnv as i,readWindowsEnv as l}from"./windows-env.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 o(e,".bashrc");case"zsh":return o(e,".zshrc");case"fish":return o(e,".config","fish","config.fish");default:return o(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const o=getShellRcFilePath();if(!o||!e(o))return!1;let s=n(o,"utf-8");const c=s,i=[...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 i)s=s.replace(e,"");if(s!==c)return r(o,s,"utf-8"),t.info(`Cleaned up ANTHROPIC_* environment variables from ${o}`),!0}catch(e){t.warn("Failed to cleanup shell environment variables:",e),t.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}export function cleanupWindowsEnvVars(f){const a=[];if("win32"!==process.platform||0===f.length)return{machineLeft:a};const p=[];for(const e of f)for(const n of["user","machine"])if(void 0!==l(n,e))try{i(n,e),p.push(`${n}:${e}`)}catch(r){"machine"===n&&a.push(e),t.logError("envCleanup.cleanupWindowsEnvVars",r)}p.length>0&&(c(),t.info(`Windows env cleanup: ${p.join(" ")}`));for(const c of function(){const e=s(),n=[];for(const r of[o(e,"Documents"),o(e,"OneDrive","Documents"),o(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(o(r,e,"Microsoft.PowerShell_profile.ps1"),o(r,e,"profile.ps1"));return n}())try{if(!e(c))continue;const o=n(c,"utf-8");let s=o;for(const e of f)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${e}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==o&&(r(c,s,"utf-8"),t.info(`Removed ANTHROPIC_* assignments from ${c}`))}catch(e){t.logError("envCleanup.powerShellProfile",e)}return{machineLeft:a}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];cleanupShellRcEnvVars(),f=cleanupWindowsEnvVars(e).machineLeft;for(const n of e)delete process.env[n];return[...e]}let f=[];export function machineEnvVarsLeft(){return f}
@@ -62,6 +62,14 @@ export interface CodexRules {
62
62
  /** Window every model is capped to when the user turns 1M context off. */
63
63
  standardContextWindow: number;
64
64
  }
65
+ /** Antigravity CLI rules. */
66
+ export interface AgyRules {
67
+ /**
68
+ * Models offered through agy's gateway mode (`AGY_LLM_GATEWAY_MODELS`), in menu order; the first
69
+ * reachable one is agy's default. Only ids in agy's built-in catalog: anything else gets no native tools.
70
+ */
71
+ gatewayModels: string[];
72
+ }
65
73
  export interface ModelRegistryData {
66
74
  defaultModels: Models;
67
75
  /** Earlier `defaultModels` values per slot; a profile still holding one follows the current default. */
@@ -75,6 +83,7 @@ export interface ModelRegistryData {
75
83
  claudeDesktop?: Partial<ClaudeDesktopRules>;
76
84
  gatewayModels?: Partial<GatewayModelRules>;
77
85
  codex?: Partial<CodexRules>;
86
+ agy?: Partial<AgyRules>;
78
87
  /** Oldest tool release vibecli's written config works with (tool id → semver). */
79
88
  toolMinVersions?: Record<string, string>;
80
89
  /** Addresses the gateway answers on, in the operator's order; used until the gateway's own list is cached. */
@@ -103,6 +112,7 @@ export declare function getClaudeDesktopRules(): ClaudeDesktopRules;
103
112
  export declare function getGatewayModelRules(): GatewayModelRules;
104
113
  export declare function getBuiltinGatewayAddresses(): GatewayAddress[];
105
114
  export declare function getCodexRules(): CodexRules;
115
+ export declare function getAgyRules(): AgyRules;
106
116
  /** Compare dotted numeric versions (`2.1.9` < `2.1.10`); missing parts count as 0. */
107
117
  export declare function compareVersions(a: string, b: string): number;
108
118
  export declare function getToolMinVersion(toolName: string): string | null;
@@ -1 +1 @@
1
- import{dirname as e,join as t}from"path";import{fileURLToPath as o}from"url";import{existsSync as n,readFileSync as r}from"fs";const l=e(o(import.meta.url));let s=null;function i(){return s||(s=function(){const e=[t(l,"..","..","models.json"),t(l,"..","models.json"),t(l,"models.json")];for(const t of e)if(n(t))return JSON.parse(r(t,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}()),s}export function getDefaultModels(){return{...i().defaultModels}}export function isRetiredDefaultModel(e,t){return i().retiredDefaultModels?.[e]?.includes(t)??!1}export function getDefaultToolModel(){return i().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const t=i().toolDefaults;return t&&Object.prototype.hasOwnProperty.call(t,e)?(t[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...i().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=i().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,[...t]]))}export function getClaudeDesktopRules(){const e=i().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=i().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e})),retired:[...e.retired??[]]}}export function getBuiltinGatewayAddresses(){return(i().gatewayAddresses??[]).map(e=>({...e}))}export function getCodexRules(){return{standardContextWindow:i().codex?.standardContextWindow??272e3}}export function compareVersions(e,t){const o=e.split(".").map(e=>parseInt(e,10)||0),n=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(o.length,n.length);e++){const t=(o[e]??0)-(n[e]??0);if(0!==t)return t}return 0}export function getToolMinVersion(e){return i().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){s=null}
1
+ import{dirname as e,join as t}from"path";import{fileURLToPath as o}from"url";import{existsSync as n,readFileSync as r}from"fs";const l=e(o(import.meta.url));let s=null;function u(){return s||(s=function(){const e=[t(l,"..","..","models.json"),t(l,"..","models.json"),t(l,"models.json")];for(const t of e)if(n(t))return JSON.parse(r(t,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}()),s}export function getDefaultModels(){return{...u().defaultModels}}export function isRetiredDefaultModel(e,t){return u().retiredDefaultModels?.[e]?.includes(t)??!1}export function getDefaultToolModel(){return u().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const t=u().toolDefaults;return t&&Object.prototype.hasOwnProperty.call(t,e)?(t[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,t])=>[e,[...t]]))}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})),retired:[...e.retired??[]]}}export function getBuiltinGatewayAddresses(){return(u().gatewayAddresses??[]).map(e=>({...e}))}export function getCodexRules(){return{standardContextWindow:u().codex?.standardContextWindow??272e3}}export function getAgyRules(){return{gatewayModels:[...u().agy?.gatewayModels??[]]}}export function compareVersions(e,t){const o=e.split(".").map(e=>parseInt(e,10)||0),n=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(o.length,n.length);e++){const t=(o[e]??0)-(n[e]??0);if(0!==t)return t}return 0}export function getToolMinVersion(e){return u().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){s=null}
@@ -1,6 +1,3 @@
1
- type RegRunner = (args: string[]) => string;
2
- /** 测试注入假的 reg.exe 与广播(非 Windows 没有注册表);传 null 恢复默认。 */
3
- export declare function setUserEnvRunnersForTests(runner: RegRunner | null, onBroadcast?: () => void): void;
4
1
  export interface PersistentEnvResult {
5
2
  /** rc 文件里加了加载行(新开终端才生效);Windows 为空。 */
6
3
  rcFiles: string[];
@@ -14,4 +11,3 @@ export declare function writePersistentEnv(id: string, envFile: string, vars: Re
14
11
  export declare function removePersistentEnv(id: string, envFile: string, names: readonly string[]): void;
15
12
  /** 读回 env 文件里的变量;文件不存在或没有内容时为空对象。 */
16
13
  export declare function readPersistentEnvFile(envFile: string): Record<string, string>;
17
- export {};
@@ -1 +1 @@
1
- import{execFileSync as t,spawn as n}from"child_process";import{chmodSync as e,existsSync as o,readFileSync as r,realpathSync as s,unlinkSync as i}from"fs";import{join as c}from"path";import{logger as f}from"../utils/logger.js";import{getShellRcFilePath as u}from"./env-cleanup.js";import{atomicWriteFile as l,backupBeforeWrite as p}from"./tools/backup.js";import{toolHome as a}from"./tools/types.js";const d=t=>`# vibecli:${t}`;function m(){const t=a(),n=new Set,e=u();e&&n.add(e);for(const e of[".zshrc",".bashrc"]){const r=c(t,e);o(r)&&n.add(r)}return[...n]}function v(t,n,e){const o=`"${function(t){const n=a();return t.startsWith(n+"/")?`$HOME/${t.slice(n.length+1)}`:t}(n)}"`;return t.endsWith(".fish")?`test -f ${o}; and source ${o} ${d(e)}`:`[ -f ${o} ] && . ${o} ${d(e)}`}function E(t,n){const e=o(t)?s(t):t;p(e),l(e,n)}function $(t,n){return t.split("\n").filter(t=>!t.trimEnd().endsWith(d(n))).join("\n")}function h(t,n){if(/['\r\n]/.test(n))throw new Error(`${t} contains a quote or newline and cannot be written to a shell env file`)}const w="HKCU\\Environment",b=n=>t("reg.exe",n,{encoding:"utf-8",windowsHide:!0,timeout:15e3,stdio:["ignore","pipe","pipe"]});let g=b,j=()=>{const t=n("powershell.exe",["-NoProfile","-NonInteractive","-Command","[Environment]::SetEnvironmentVariable('VIBECLI_ENV_REFRESH',$null,'User')"],{detached:!0,stdio:"ignore",windowsHide:!0});t.on("error",t=>f.logError("persistentEnv.broadcast",t)),t.unref()};export function setUserEnvRunnersForTests(t,n){g=t??b,n&&(j=n)}function x(t){let n;try{n=g(["query",w,"/v",t])}catch{return}const e=n.match(new RegExp(String.raw`^\s*${t}\s+REG_(?:EXPAND_)?SZ\s+(.*?)\r?$`,"m"));return e?e[1]:void 0}export function writePersistentEnv(t,n,s){for(const[t,n]of Object.entries(s))h(t,n);const i=Object.entries(s).map(([t,n])=>`export ${t}='${n}'`).join("\n");p(n),l(n,`# Written by vibecli. Loaded from your shell profile.\n${i}\n`,384),e(n,384);for(const[t,n]of Object.entries(s))process.env[t]=n;if("win32"===process.platform){for(const[t,n]of Object.entries(s))g(["add",w,"/v",t,"/t","REG_SZ","/d",n,"/f"]);return j(),{rcFiles:[]}}const c=[];for(const e of m()){const s=o(e)?r(e,"utf-8"):"",i=v(e,n,t);if(s.split("\n").some(t=>t.trimEnd()===i)){c.push(e);continue}const f=$(s,t).replace(/\n*$/,"");E(e,`${f?f+"\n\n":""}${i}\n`),c.push(e)}return{rcFiles:c}}export function removePersistentEnv(t,n,e){const s=readPersistentEnvFile(n);if(o(n)&&(p(n),i(n)),"win32"===process.platform){let t=!1;for(const n of e)if(void 0!==s[n]&&x(n)===s[n])try{g(["delete",w,"/v",n,"/f"]),t=!0}catch(t){f.logError("persistentEnv.remove",t)}return void(t&&j())}for(const n of m()){if(!o(n))continue;const e=r(n,"utf-8"),s=$(e,t);s!==e&&E(n,s)}}export function readPersistentEnvFile(t){const n={};if(!o(t))return n;for(const e of r(t,"utf-8").split("\n")){const t=e.match(/^export ([A-Z_][A-Z0-9_]*)='([^']*)'$/);t&&(n[t[1]]=t[2])}return n}
1
+ import{chmodSync as t,existsSync as n,readFileSync as o,realpathSync as r,unlinkSync as e}from"fs";import{join as s}from"path";import{logger as i}from"../utils/logger.js";import{getShellRcFilePath as c}from"./env-cleanup.js";import{broadcastEnvChange as f,deleteWindowsEnv as u,readWindowsEnv as p,setUserEnv as l}from"./windows-env.js";import{atomicWriteFile as m,backupBeforeWrite as a}from"./tools/backup.js";import{toolHome as $}from"./tools/types.js";const d=t=>`# vibecli:${t}`;function h(){const t=$(),o=new Set,r=c();r&&o.add(r);for(const r of[".zshrc",".bashrc"]){const e=s(t,r);n(e)&&o.add(e)}return[...o]}function v(t,n,o){const r=`"${function(t){const n=$();return t.startsWith(n+"/")?`$HOME/${t.slice(n.length+1)}`:t}(n)}"`;return t.endsWith(".fish")?`test -f ${r}; and source ${r} ${d(o)}`:`[ -f ${r} ] && . ${r} ${d(o)}`}function j(t,o){const e=n(t)?r(t):t;a(e),m(e,o)}function b(t,n){return t.split("\n").filter(t=>!t.trimEnd().endsWith(d(n))).join("\n")}function w(t,n){if(/['\r\n]/.test(n))throw new Error(`${t} contains a quote or newline and cannot be written to a shell env file`)}export function writePersistentEnv(r,e,s){for(const[t,n]of Object.entries(s))w(t,n);const i=Object.entries(s).map(([t,n])=>`export ${t}='${n}'`).join("\n");a(e),m(e,`# Written by vibecli. Loaded from your shell profile.\n${i}\n`,384),t(e,384);for(const[t,n]of Object.entries(s))process.env[t]=n;if("win32"===process.platform){for(const[t,n]of Object.entries(s))l(t,n);return f(),{rcFiles:[]}}const c=[];for(const t of h()){const s=n(t)?o(t,"utf-8"):"",i=v(t,e,r);if(s.split("\n").some(t=>t.trimEnd()===i)){c.push(t);continue}const f=b(s,r).replace(/\n*$/,"");j(t,`${f?f+"\n\n":""}${i}\n`),c.push(t)}return{rcFiles:c}}export function removePersistentEnv(t,r,s){const c=readPersistentEnvFile(r);if(n(r)&&(a(r),e(r)),"win32"===process.platform){let t=!1;for(const n of s)if(void 0!==c[n]&&p("user",n)===c[n])try{u("user",n),t=!0}catch(t){i.logError("persistentEnv.remove",t)}return void(t&&f())}for(const r of h()){if(!n(r))continue;const e=o(r,"utf-8"),s=b(e,t);s!==e&&j(r,s)}}export function readPersistentEnvFile(t){const r={};if(!n(t))return r;for(const n of o(t,"utf-8").split("\n")){const t=n.match(/^export ([A-Z_][A-Z0-9_]*)='([^']*)'$/);t&&(r[t[1]]=t[2])}return r}
@@ -1 +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()]};
1
+ import{existsSync as t,readFileSync as r}from"fs";import{join as e}from"path";import{i18n as n}from"../i18n.js";import{prettyModelName as o}from"../gateway-models.js";import{getAgyRules as i}from"../model-registry.js";import{logger as a}from"../../utils/logger.js";import{readPersistentEnvFile as s,removePersistentEnv as l,writePersistentEnv as c}from"../persistent-env.js";import{backupBeforeWrite as p,atomicWriteFile as g}from"./backup.js";import{mirrorInstallCommand as m}from"./tool-installs.js";import{toolHome as u}from"./types.js";const d="GEMINI_API_KEY",f="GOOGLE_GEMINI_BASE_URL",y="AGY_LLM_GATEWAY_URL",v="AGY_LLM_GATEWAY_API_KEY",h="AGY_LLM_GATEWAY_MODELS",A=[d,f,y,v,h],_="gemini",j=()=>e(u(),".gemini","antigravity-cli"),b=()=>e(j(),"settings.json"),E=()=>e(j(),"vibeapi.env"),w="https://cnb.cool/vibeapi/agy/-/releases/latest/download",P={command:"agy",native:{binDir:"win32"===process.platform?["AppData","Local","agy","bin"]:[".local","bin"],updateArgs:["update"],dataDirs:[]},mirrorScript:{sh:`${w}/install.sh`,ps1:`${w}/install.ps1`}};function C(){if(!t(b()))return{};const e=r(b(),"utf-8");if(!e.trim())return{};try{const t=JSON.parse(e);if(!(n=t)||"object"!=typeof n||Array.isArray(n))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 n}function L(t){p(b()),g(b(),JSON.stringify(t,null,2)+"\n")}function M(t){return(t||"").replace(/\/+$/,"").replace(/\/v1(beta)?$/,"")}function G(t){const r=i().gatewayModels,e=t?r.filter(r=>t.models.includes(r)):[];return e.length>0?e:r}function K(t,r,e){return c("agy",E(),{[d]:t,[f]:r,[y]:r,[v]:t,[h]:e.join(",")}).rcFiles}const S=t=>o(t.replace(/-preview$/,""));let Y=null,k=null;export const antigravityAdapter={name:"agy",displayName:"Antigravity CLI",command:"agy",installCommand:m(P),installSpec:P,configPath:b(),wantsModelCatalog:!0,loadPrivateConfig(t){const r=C(),e=G(t.catalog);Y=K(t.apiKey,M(t.baseUrl),e),k=e,r.modelProvider!==_&&(r.modelProvider=_,L(r))},unloadPrivateConfig(){try{const t=C();t.modelProvider===_&&(delete t.modelProvider,L(t))}catch(t){a.logError("antigravityAdapter.unloadPrivateConfig",t)}l("agy",E(),A)},listedModels(){if(null===antigravityAdapter.detectCurrentConfig().apiKey)return null;const t=s(E())[h];return t?t.split(",").filter(Boolean):[]},refreshModelMenu(t){const r=s(E()),e=G(t.catalog),n=r[f]||M(t.baseUrl),o=r[d]||t.apiKey;r[h]===e.join(",")&&r[y]===n&&r[v]===o||K(o,n,e)},detectCurrentConfig(){try{if(C().modelProvider!==_)return{apiKey:null}}catch{return{apiKey:null}}const t=s(E())[d];return{apiKey:t&&t.trim()?t:null}},getConfig(){try{return C()}catch(t){return a.logError("antigravityAdapter.getConfig",t),null}},applyNotes(){const t=[];if(k&&k.length>0){const r=k.map(S);t.push({kind:"summary",text:n.t("tools.agy.menu_written",{count:String(r.length),list:r.join(n.t("tools.grok.list_separator")),default:r[0]})})}return null===Y||(0===Y.length?t.push({kind:"action",text:n.t("tools.agy.reopen_terminal_windows")}):t.push({kind:"action",text:n.t("tools.agy.reopen_terminal",{rc:Y.join(", ")})})),t},backupPaths:()=>[b(),E()],forceResetPaths:()=>[E()]};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Windows 持久环境变量(用户级 / 系统级)的读写,统一用 reg.exe 直接操作注册表。
3
+ * 不用 .NET 的 `[Environment]::SetEnvironmentVariable(..., 'User' | 'Machine')`:它写完同步广播
4
+ * WM_SETTINGCHANGE,不带 SMTO_ABORTIFHUNG,每个无响应的窗口等 1 秒,客户机器上整条命令会超时
5
+ * (`spawnSync powershell.exe ETIMEDOUT`)。改完由 `broadcastEnvChange()` 在后台广播,不等它结束。
6
+ */
7
+ export type EnvScope = 'user' | 'machine';
8
+ type RegRunner = (args: string[]) => string;
9
+ /** 测试注入假的 reg.exe 与广播(非 Windows 没有注册表);传 null 恢复默认。 */
10
+ export declare function setWindowsEnvRunnersForTests(runner: RegRunner | null, onBroadcast?: () => void): void;
11
+ /** 读注册表里的值;不存在时为 undefined(reg query 以非零退出)。 */
12
+ export declare function readWindowsEnv(scope: EnvScope, name: string): string | undefined;
13
+ export declare function setUserEnv(name: string, value: string): void;
14
+ /** 删除一个值;系统级没有管理员权限时 reg.exe 拒绝,异常交给调用方。 */
15
+ export declare function deleteWindowsEnv(scope: EnvScope, name: string): void;
16
+ /** 通知已打开的窗口(资源管理器等)环境变量变了,新开的终端才拿得到;后台进行。 */
17
+ export declare function broadcastEnvChange(): void;
18
+ export {};
@@ -0,0 +1 @@
1
+ import{execFileSync as e,spawn as n}from"child_process";import{logger as o}from"../utils/logger.js";const r={user:"HKCU\\Environment",machine:"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"},t=n=>e("reg.exe",n,{encoding:"utf-8",windowsHide:!0,timeout:15e3,stdio:["ignore","pipe","pipe"]}),i=()=>{const e=n("powershell.exe",["-NoProfile","-NonInteractive","-Command","[Environment]::SetEnvironmentVariable('VIBECLI_ENV_REFRESH',$null,'User')"],{detached:!0,stdio:"ignore",windowsHide:!0});e.on("error",e=>o.logError("windowsEnv.broadcast",e)),e.unref()};let s=t,d=i;export function setWindowsEnvRunnersForTests(e,n){s=e??t,d=e?n??(()=>{}):i}export function readWindowsEnv(e,n){let o;try{o=s(["query",r[e],"/v",n])}catch{return}const t=o.match(new RegExp(String.raw`^\s*${n}\s+REG_(?:EXPAND_)?SZ\s+(.*?)\r?$`,"im"));return t?t[1]:void 0}export function setUserEnv(e,n){s(["add",r.user,"/v",e,"/t","REG_SZ","/d",n,"/f"])}export function deleteWindowsEnv(e,n){s(["delete",r[e],"/v",n,"/f"])}export function broadcastEnvChange(){d()}
@@ -359,6 +359,7 @@
359
359
  "tools": {
360
360
  "version_outdated": "version {{current}} is too old (needs {{min}} or later); upgrade with {{upgrade}}",
361
361
  "agy": {
362
+ "menu_written": "{{count}} models in the menu ({{list}}), default {{default}}",
362
363
  "reopen_terminal": "Key and address were added to {{rc}}; open a new terminal before running agy",
363
364
  "reopen_terminal_windows": "Key and address were saved as user environment variables; reopen the terminal before running agy"
364
365
  },
@@ -359,6 +359,7 @@
359
359
  "tools": {
360
360
  "version_outdated": "版本 {{current}} 过旧,需要 {{min}} 及以上,运行 {{upgrade}} 升级",
361
361
  "agy": {
362
+ "menu_written": "模型菜单 {{count}} 个({{list}}),默认 {{default}}",
362
363
  "reopen_terminal": "Key 与地址已写入 {{rc}},新开一个终端再运行 agy",
363
364
  "reopen_terminal_windows": "Key 与地址已写入用户环境变量,重新打开终端再运行 agy"
364
365
  },
package/dist/models.json CHANGED
@@ -283,6 +283,15 @@
283
283
  "codex": {
284
284
  "standardContextWindow": 272000
285
285
  },
286
+ "agy": {
287
+ "gatewayModels": [
288
+ "gemini-4-argon",
289
+ "gemini-3.8-flash",
290
+ "gemini-3.7-flash",
291
+ "gemini-3.6-flash",
292
+ "gemini-3.1-pro-preview"
293
+ ]
294
+ },
286
295
  "toolMinVersions": {
287
296
  "codex": "0.122.0",
288
297
  "claude-code": "2.1.291",
package/models.json CHANGED
@@ -283,6 +283,15 @@
283
283
  "codex": {
284
284
  "standardContextWindow": 272000
285
285
  },
286
+ "agy": {
287
+ "gatewayModels": [
288
+ "gemini-4-argon",
289
+ "gemini-3.8-flash",
290
+ "gemini-3.7-flash",
291
+ "gemini-3.6-flash",
292
+ "gemini-3.1-pro-preview"
293
+ ]
294
+ },
286
295
  "toolMinVersions": {
287
296
  "codex": "0.122.0",
288
297
  "claude-code": "2.1.291",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/api-helper",
3
- "version": "0.0.89",
3
+ "version": "0.0.91",
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",