@vibeapi/cli 0.0.81 → 0.0.83

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.
@@ -5,7 +5,7 @@ import type { GatewayClientModel } from './api-validator.js';
5
5
  * model menus, and the shared context rules: each model compacts at
6
6
  * `autoCompactRatio` (80%) of its window unless the gateway sets a point.
7
7
  */
8
- export type GatewayModelTool = 'codex' | 'claude-code';
8
+ export type GatewayModelTool = 'codex' | 'claude-code' | 'grok';
9
9
  /** Auto-compaction point for a window: the explicit value (capped at the window) or the ratio. */
10
10
  export declare function autoCompactTokens(window: number, explicit?: number): number;
11
11
  /**
@@ -13,7 +13,7 @@ export declare function autoCompactTokens(window: number, explicit?: number): nu
13
13
  * (`/api/platform/vibecode/config`) its lists come first — fields it leaves out keep
14
14
  * the built-in values, and Claude models only come from it when `models.json` lists
15
15
  * them too (so a model removed there, like Haiku for Codex, stays out); Codex also
16
- * gets the `gemini` list. Built-in entries the lists lack are added (see
16
+ * gets the `gemini` list, Grok Build only the `grok` list. Built-in entries the lists lack are added (see
17
17
  * `withBuiltInExtras`); a `hidden` row on the gateway keeps one out. Without the
18
18
  * config, the built-in list from `models.json` → `gatewayModels`.
19
19
  */
@@ -1 +1 @@
1
- import{getGatewayModelRules as t}from"./model-registry.js";export function autoCompactTokens(e,i){return i&&i>0?Math.min(i,e):Math.floor(e*t().autoCompactRatio)}export function gatewayModelSpecs(e,i){const o=t().models,n=o.filter(t=>function(t,e){return"codex"===t?!1!==e.codex:!e.id.startsWith("claude-")&&!1!==e.claudeCode}(e,t));if(!i)return n;const d=new Set(Object.values(i).flat().filter(t=>t.hidden).map(t=>t.id)),r=Object.fromEntries(Object.entries(i).map(([t,e])=>[t,e.filter(t=>!t.hidden)])),s=new Map(("claude-code"===e?o:n).map(t=>[t.id,t])),l=(r.gemini??[]).filter(t=>!1!==o.find(e=>e.id===t.id)?.codex),a="codex"===e?[...r.codex??[],...l,...(r.claude??[]).filter(t=>t.id.startsWith("claude-")&&s.has(t.id))]:function(t,e){return[...(t.codex??[]).filter(t=>"gpt"===modelFamily(t.id)),...t.gemini??[],...t.grok??[],...(t.claude??[]).filter(t=>!t.id.startsWith("claude-"))].filter(t=>e.get(t.id)?.claudeCode??!0)}(r,s);if(0===a.length)return n.filter(t=>!d.has(t.id));const c=new Set,u=[];for(const t of a)c.has(t.id)||(c.add(t.id),u.push({...s.get(t.id),...t}));return function(t,e,i){const o=[...t];return e.forEach((t,n)=>{if(i.has(t.id)||o.some(e=>e.id===t.id))return;const d=modelFamily(t.id),r=new Set(e.slice(n+1).filter(t=>modelFamily(t.id)===d).map(t=>t.id));let s=o.findIndex(t=>r.has(t.id));if(s<0){s=o.length;for(let t=o.length-1;t>=0;t--)if(modelFamily(o[t].id)===d){s=t+1;break}}o.splice(s,0,t)}),o}(u,n,d)}const e={gpt:"GPT",gemini:"Gemini",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function modelBlurb(t,e={}){const i=[];for(const o of(t??"").split("|")){const t=o.trim();t&&(/\d\s*万?\s*输出|output\D*\d|\d\D*output/i.test(t)||(/[\d百千]\s*万?\s*上下文|context\D*\d|\d\D*context/i.test(t)?e.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"):i.push(t)))}return e.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"),i.length>0?i.join(" | "):void 0}export function prettyModelName(t){const i=t.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),o=[];for(const t of i){const i=o[o.length-1];if(/^\d+$/.test(t)&&i&&/^\d+$/.test(i)&&t.length<=2&&!/^\d{8}$/.test(t)){o[o.length-1]=`${i}.${t}`;continue}const n=t.toLowerCase();o.push(e[n]??(/^[a-z]\d/i.test(t)?t.toUpperCase():t[0].toUpperCase()+t.slice(1)))}return o.join(" ")}export function vendorNames(t){return[...new Set(t.map(t=>prettyModelName(t).split(" ")[0]))]}export function modelFamily(t){const e=t.toLowerCase();return e.startsWith("claude-")?"claude":e.startsWith("gemini")?"gemini":e.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(e)?"gpt":"other"}
1
+ import{getGatewayModelRules as e}from"./model-registry.js";export function autoCompactTokens(t,i){return i&&i>0?Math.min(i,t):Math.floor(t*e().autoCompactRatio)}export function gatewayModelSpecs(t,i){const o=e().models,n=o.filter(e=>function(e,t){return"codex"===e?!1!==t.codex:"grok"===e?"grok"===modelFamily(t.id):!t.id.startsWith("claude-")&&!1!==t.claudeCode}(t,e));if(!i)return n;const d=new Set(Object.values(i).flat().filter(e=>e.hidden).map(e=>e.id)),r=Object.fromEntries(Object.entries(i).map(([e,t])=>[e,t.filter(e=>!e.hidden)])),s=new Map(("claude-code"===t?o:n).map(e=>[e.id,e])),l=(r.gemini??[]).filter(e=>!1!==o.find(t=>t.id===e.id)?.codex),a="grok"===t?r.grok??[]:"codex"===t?[...r.codex??[],...l,...(r.claude??[]).filter(e=>e.id.startsWith("claude-")&&s.has(e.id))]:function(e,t){return[...(e.codex??[]).filter(e=>"gpt"===modelFamily(e.id)),...e.gemini??[],...e.grok??[],...(e.claude??[]).filter(e=>!e.id.startsWith("claude-"))].filter(e=>t.get(e.id)?.claudeCode??!0)}(r,s);if(0===a.length)return n.filter(e=>!d.has(e.id));const c=new Set,u=[];for(const e of a)c.has(e.id)||(c.add(e.id),u.push({...s.get(e.id),...e}));return function(e,t,i){const o=[...e];return t.forEach((e,n)=>{if(i.has(e.id)||o.some(t=>t.id===e.id))return;const d=modelFamily(e.id),r=new Set(t.slice(n+1).filter(e=>modelFamily(e.id)===d).map(e=>e.id));let s=o.findIndex(e=>r.has(e.id));if(s<0){s=o.length;for(let e=o.length-1;e>=0;e--)if(modelFamily(o[e].id)===d){s=e+1;break}}o.splice(s,0,e)}),o}(u,n,d)}const t={gpt:"GPT",gemini:"Gemini",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function modelBlurb(e,t={}){const i=[];for(const o of(e??"").split("|")){const e=o.trim();e&&(/\d\s*万?\s*输出|output\D*\d|\d\D*output/i.test(e)||(/[\d百千]\s*万?\s*上下文|context\D*\d|\d\D*context/i.test(e)?t.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"):i.push(e)))}return t.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"),i.length>0?i.join(" | "):void 0}export function prettyModelName(e){const i=e.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),o=[];for(const e of i){const i=o[o.length-1];if(/^\d+$/.test(e)&&i&&/^\d+$/.test(i)&&e.length<=2&&!/^\d{8}$/.test(e)){o[o.length-1]=`${i}.${e}`;continue}const n=e.toLowerCase();o.push(t[n]??(/^[a-z]\d/i.test(e)?e.toUpperCase():e[0].toUpperCase()+e.slice(1)))}return o.join(" ")}export function vendorNames(e){return[...new Set(e.map(e=>prettyModelName(e).split(" ")[0]))]}export function modelFamily(e){const t=e.toLowerCase();return t.startsWith("claude-")?"claude":t.startsWith("gemini")?"gemini":t.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(t)?"gpt":"other"}
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as o,readFileSync as t,writeFileSync as r}from"fs";import{dirname as n,join as s}from"path";import i from"chalk";import{configManager as l}from"./config.js";import{i18n as f}from"./i18n.js";import{resolveModelCatalog as d}from"./model-catalog.js";import{listAdapters as c}from"./tools/registry.js";import{UserActionNeeded as a}from"./tools/types.js";import{logger as u}from"../utils/logger.js";import{resolveUpdateCachePath as m}from"./auto-update.js";export const MODEL_REFRESH_INTERVAL_MS=36e5;const h=new Set(["setup","init","config","auth","enter","completion","update","lang","logs"]),p=["--json","--dry-run","--help","-h","--version","-v"],g=[];export function shouldSkipModelRefresh(e,o=process.env){if("1"===o.VIBECLI_DISABLE_MODEL_REFRESH)return!0;if(p.some(o=>e.includes(o)))return!0;const t=e.find(e=>!e.startsWith("-"));return void 0===t||h.has(t)}export async function refreshModelMenus(){const e=new Map,o=[];g.length=0;for(const t of c())if(t.refreshModelMenu&&t.listedModels)try{const r=l.getApiKeyForTool(t.name);if(!r||t.detectCurrentConfig().apiKey!==r)continue;const n=t.listedModels();if(null===n)continue;e.has(r)||e.set(r,await d(r));const s=e.get(r);if(!s)continue;t.refreshModelMenu({apiKey:r,baseUrl:l.getBaseUrl(),models:l.getModelsForTool(t.name),settings:l.getToolSettings(t.name),catalog:s});const i=t.listedModels()??[],f=i.filter(e=>!n.includes(e)),c=n.filter(e=>!i.includes(e));(f.length>0||c.length>0)&&o.push({tool:t.displayName,added:f,removed:c})}catch(e){u.logError(`modelRefresh(${t.name})`,e),e instanceof a&&g.push(e.message)}return o}export async function runModelRefresh(l,d={}){const c=d.env??process.env;if(shouldSkipModelRefresh(l,c))return[];const a=d.now??Date.now(),h=function(e){return s(n(m(e)),"model-refresh.json")}(c);if(a-function(e){try{const o=JSON.parse(t(e,"utf-8")).refreshed_at;return"number"==typeof o?o:0}catch{return 0}}(h)<36e5)return[];let p=[];try{p=await refreshModelMenus(),e(n(h))||o(n(h),{recursive:!0}),r(h,JSON.stringify({refreshed_at:a})+"\n")}catch(e){u.logError("runModelRefresh",e)}const M=d.output??(e=>console.log(i.gray(e)));for(const e of g)M(e);for(const e of p){const o=[e.added.length>0?f.t("model_refresh.added",{models:e.added.join(", ")}):"",e.removed.length>0?f.t("model_refresh.removed",{models:e.removed.join(", ")}):""].filter(Boolean);M(f.t("model_refresh.changed",{tool:e.tool,changes:o.join(";")}))}return p}
1
+ import{existsSync as e,mkdirSync as o,readFileSync as t,writeFileSync as r}from"fs";import{dirname as n,join as s}from"path";import i from"chalk";import{configManager as l}from"./config.js";import{i18n as f}from"./i18n.js";import{resolveModelCatalog as d}from"./model-catalog.js";import{listAdapters as c}from"./tools/registry.js";import{UserActionNeeded as a}from"./tools/types.js";import{logger as u}from"../utils/logger.js";import{resolveUpdateCachePath as m}from"./auto-update.js";export const MODEL_REFRESH_INTERVAL_MS=36e5;const h=new Set(["setup","init","config","auth","enter","completion","update","lang","logs"]),p=["--json","--dry-run","--help","-h","--version","-v"],g=[];export function shouldSkipModelRefresh(e,o=process.env){if("1"===o.VIBECLI_DISABLE_MODEL_REFRESH)return!0;if(p.some(o=>e.includes(o)))return!0;const t=e.find(e=>!e.startsWith("-"));return void 0!==t&&h.has(t)}export async function refreshModelMenus(){const e=new Map,o=[];g.length=0;for(const t of c())if(t.refreshModelMenu&&t.listedModels)try{const r=l.getApiKeyForTool(t.name);if(!r||t.detectCurrentConfig().apiKey!==r)continue;const n=t.listedModels();if(null===n)continue;e.has(r)||e.set(r,await d(r));const s=e.get(r);if(!s)continue;t.refreshModelMenu({apiKey:r,baseUrl:l.getBaseUrl(),models:l.getModelsForTool(t.name),settings:l.getToolSettings(t.name),catalog:s});const i=t.listedModels()??[],f=i.filter(e=>!n.includes(e)),c=n.filter(e=>!i.includes(e));(f.length>0||c.length>0)&&o.push({tool:t.displayName,added:f,removed:c})}catch(e){u.logError(`modelRefresh(${t.name})`,e),e instanceof a&&g.push(e.message)}return o}export async function runModelRefresh(l,d={}){const c=d.env??process.env;if(shouldSkipModelRefresh(l,c))return[];const a=d.now??Date.now(),h=function(e){return s(n(m(e)),"model-refresh.json")}(c);if(a-function(e){try{const o=JSON.parse(t(e,"utf-8")).refreshed_at;return"number"==typeof o?o:0}catch{return 0}}(h)<36e5)return[];let p=[];try{p=await refreshModelMenus(),e(n(h))||o(n(h),{recursive:!0}),r(h,JSON.stringify({refreshed_at:a})+"\n")}catch(e){u.logError("runModelRefresh",e)}const M=d.output??(e=>console.log(i.gray(e)));for(const e of g)M(e);for(const e of p){const o=[e.added.length>0?f.t("model_refresh.added",{models:e.added.join(", ")}):"",e.removed.length>0?f.t("model_refresh.removed",{models:e.removed.join(", ")}):""].filter(Boolean);M(f.t("model_refresh.changed",{tool:e.tool,changes:o.join(";")}))}return p}
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as t}from"fs";import{join as r}from"path";import*as o from"@iarna/toml";import{logger as n}from"../../utils/logger.js";import{BRAND_NAME as i,PROVIDER_KEY as l}from"../brand.js";import{backupBeforeWrite as s,atomicWriteFile as a}from"./backup.js";import{pickModel as m,toolHome as d,withV1 as c}from"./types.js";import{getToolDefaultModel as f}from"../model-registry.js";const p=()=>r(r(d(),".grok"),"config.toml"),g=l,u="win32"===process.platform?'powershell -c "irm https://x.ai/cli/install.ps1 | iex"':"curl -fsSL https://x.ai/cli/install.sh | bash";function y(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function k(e,t){return y(e[t])||(e[t]={}),e[t]}function h(){if(!e(p()))return{};const r=t(p(),"utf-8");if(!r.trim())return{};try{const e=o.parse(r);if(!y(e))throw new Error("config.toml root must be a TOML table");return e}catch(e){throw new Error(`Existing ~/.grok/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}export const grokAdapter={name:"grok",displayName:"Grok Build",command:"grok",installCommand:u,configPath:p(),loadPrivateConfig(e){const t=h();k(t,"endpoints").models_base_url=c(e.baseUrl),k(t,"models").default=g;const r=k(t,"model"),n=y(r[g])?{...r[g]}:{};r[g]={...n,name:i,model:m(e.models,f("grok")),api_key:e.apiKey,context_window:5e5,api_backend:"responses",reasoning_summary:"concise"},s(p()),a(p(),o.stringify(t))},unloadPrivateConfig(){if(!e(p()))return;let t;try{t=h()}catch(e){return void n.logError("grokAdapter.unloadPrivateConfig",e)}y(t.model)&&(delete t.model[g],0===Object.keys(t.model).length&&delete t.model),y(t.models)&&t.models.default===g&&(delete t.models.default,0===Object.keys(t.models).length&&delete t.models),y(t.endpoints)&&(delete t.endpoints.models_base_url,0===Object.keys(t.endpoints).length&&delete t.endpoints),s(p()),a(p(),o.stringify(t))},detectCurrentConfig(){try{const e=h(),t=y(e.model)?e.model:{},r=y(t[g])?t[g]:null,o=r?r.api_key:null;return{apiKey:"string"==typeof o&&o.trim()?o:null}}catch{return{apiKey:null}}},getConfig(){try{return h()}catch(e){return n.logError("grokAdapter.getConfig",e),null}}};
1
+ import{existsSync as e,readFileSync as t}from"fs";import{join as o}from"path";import*as r from"@iarna/toml";import{logger as n}from"../../utils/logger.js";import{PROVIDER_KEY as i}from"../brand.js";import{backupBeforeWrite as s,atomicWriteFile as l}from"./backup.js";import{pickModel as d,toolHome as a,withV1 as f}from"./types.js";import{getToolDefaultModel as m}from"../model-registry.js";import{gatewayModelSpecs as c,modelBlurb as g,modelFamily as u,prettyModelName as p}from"../gateway-models.js";const y=()=>o(o(a(),".grok"),"config.toml"),h=i,k=`${i}-`,b=["low","medium","high","xhigh"],w=e=>`${k}${e}`,_=e=>e===h||e.startsWith(k),j="win32"===process.platform?'powershell -c "irm https://x.ai/cli/install.ps1 | iex"':"curl -fsSL https://x.ai/cli/install.sh | bash";function x(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function C(e,t){return x(e[t])||(e[t]={}),e[t]}function v(){if(!e(y()))return{};const o=t(y(),"utf-8");if(!o.trim())return{};try{const e=r.parse(o);if(!x(e))throw new Error("config.toml root must be a TOML table");return e}catch(e){throw new Error(`Existing ~/.grok/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function M(e){return x(e.model)?Object.entries(e.model).filter(e=>_(e[0])&&x(e[1])):[]}function E(e,t){let o=c("grok",e.catalog?.clientModels);if(e.catalog){const t=new Set(e.catalog.models);o=o.filter(e=>t.has(e.id))}return o.some(e=>e.id===t)?o:[{id:t},...o]}function A(e,t,o){C(e,"endpoints").models_base_url=f(t.baseUrl);const r=C(e,"model"),n=new Map(M(e));for(const e of n.keys())delete r[e];for(const e of o){const o=w(e.id),i={...n.get(o)??{},name:e.name??p(e.id),model:e.id,base_url:f(t.baseUrl),api_key:t.apiKey,context_window:e.contextWindow??5e5,api_backend:"responses",reasoning_summary:"concise"};"grok"===u(e.id)&&(i.supports_reasoning_effort=!0,i.reasoning_efforts=b);const s=g(e.description);s?i.description=s:delete i.description,r[o]=i}}export const grokAdapter={name:"grok",displayName:"Grok Build",command:"grok",installCommand:j,configPath:y(),wantsModelCatalog:!0,loadPrivateConfig(e){const t=v(),o=d(e.models,m("grok"));A(t,e,E(e,o)),C(t,"models").default=w(o),s(y()),l(y(),r.stringify(t))},unloadPrivateConfig(){if(!e(y()))return;let t;try{t=v()}catch(e){return void n.logError("grokAdapter.unloadPrivateConfig",e)}if(x(t.model)){for(const[e]of M(t))delete t.model[e];0===Object.keys(t.model).length&&delete t.model}x(t.models)&&"string"==typeof t.models.default&&_(t.models.default)&&(delete t.models.default,0===Object.keys(t.models).length&&delete t.models),x(t.endpoints)&&(delete t.endpoints.models_base_url,0===Object.keys(t.endpoints).length&&delete t.endpoints),s(y()),l(y(),r.stringify(t))},detectCurrentConfig(){try{const e=v(),t=M(e),o=x(e.models)?e.models.default:void 0,r=t.find(([e])=>e===o)?.[1]??t[0]?.[1],n=r?r.api_key:null;return{apiKey:"string"==typeof n&&n.trim()?n:null}}catch{return{apiKey:null}}},listedModels(){try{const e=M(v());return e.length>0?e.map(([,e])=>String(e.model)):null}catch{return null}},refreshModelMenu(e){const t=v(),o=C(t,"models"),n="string"==typeof o.default?o.default:void 0,i=n?M(t).find(([e])=>e===n)?.[1].model:void 0,a="string"==typeof i&&n!==h&&e.catalog.models.includes(i)?i:d(e.models,m("grok")),f=r.stringify(t);A(t,e,E(e,a)),(void 0===n||_(n))&&(o.default=w(a)),r.stringify(t)!==f&&(s(y()),l(y(),r.stringify(t)))},getConfig(){try{return v()}catch(e){return n.logError("grokAdapter.getConfig",e),null}}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.81",
3
+ "version": "0.0.83",
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",