@vibeapi/api-helper 0.0.94 → 0.0.96

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.
@@ -1 +1 @@
1
- import{logger as e}from"../utils/logger.js";import{bundledClientConfig as t,parseClientConfig as n,readCachedClientConfig as o,writeCachedClientConfig as i}from"./client-config.js";import{configManager as r}from"./config.js";import{getBuiltinGatewayAddresses as c,reloadRegistry as s}from"./model-registry.js";export const CLIENT_CONFIG_TTL_MS=3e5;function f(e){try{return new URL(e).origin}catch{return e.replace(/\/+$/,"")}}export function clientConfigSite(e=r.getBaseUrl()){const t=f(e);return c().some(e=>f(e.url)===t)?"vibeapi":t}let l=null;export function lastClientConfigStatus(){return l}function a(e){const n=o();if(n&&n.site===clientConfigSite())return{config:n.config,source:"cache",revision:n.config.revision,fetchedAt:n.fetchedAt,problem:e};const i=t();return i?{config:i,source:"bundled",revision:i.revision,problem:e}:{config:null,source:null,problem:e}}export async function refreshClientConfig(c={}){const{force:f=!1,timeoutMs:g=8e3,fetchFn:u=fetch,now:d=Date.now()}=c;if("1"===process.env.VIBECLI_DISABLE_CLIENT_CONFIG_FETCH)return l=a(),l;const h=clientConfigSite(),m=o(),p=m&&m.site===h?m:null;if(!f&&p&&d-p.fetchedAt<3e5)return l={config:p.config,source:"cache",revision:p.config.revision,fetchedAt:p.fetchedAt},l;const C=p?.config??("vibeapi"===h?t():null),v=new AbortController,b=setTimeout(()=>v.abort(),g);try{const t={};p?.etag&&(t["If-None-Match"]=p.etag);const o=await u(`${r.getBaseUrl()}/api/platform/vibecode/config`,{method:"GET",headers:t,signal:v.signal});if(304===o.status&&p)return i({...p,fetchedAt:d}),l={config:p.config,source:"cloud",revision:p.config.revision,fetchedAt:d},l;if(!o.ok)return l=a(`HTTP ${o.status}`),l;const c=await o.json(),{config:f,problem:g}=n(c?.data,C);if(!f)return e.warn(`Gateway client config refused: ${g}`),l=a(`refused: ${g}`),l;g&&e.warn(`Gateway client config: ${g}`);const m=o.headers.get("etag")??void 0;return i({site:h,fetchedAt:d,config:f,...m?{etag:m}:{}}),s(),l={config:f,source:"cloud",revision:f.revision,fetchedAt:d,...g?{problem:g}:{}},l}catch(t){return e.logError("refreshClientConfig",t),l=a(t instanceof Error?t.message:String(t)),l}finally{clearTimeout(b)}}
1
+ import{logger as e}from"../utils/logger.js";import{bundledClientConfig as t,parseClientConfig as n,readCachedClientConfig as o,setClientConfigSiteResolver as i,writeCachedClientConfig as r}from"./client-config.js";import{configManager as c}from"./config.js";import{getBuiltinGatewayAddresses as f,reloadRegistry as s}from"./model-registry.js";export const CLIENT_CONFIG_TTL_MS=3e5;function l(e){try{return new URL(e).origin}catch{return e.replace(/\/+$/,"")}}export function clientConfigSite(e=c.getBaseUrl()){const t=l(e);return f().some(e=>l(e.url)===t)?"vibeapi":t}i(()=>clientConfigSite());let a=null;export function lastClientConfigStatus(){return a}function g(e){const n=o();if(n&&n.site===clientConfigSite())return{config:n.config,source:"cache",revision:n.config.revision,fetchedAt:n.fetchedAt,problem:e};const i=t();return i?{config:i,source:"bundled",revision:i.revision,problem:e}:{config:null,source:null,problem:e}}export async function refreshClientConfig(i={}){const{force:f=!1,timeoutMs:l=8e3,fetchFn:u=fetch,now:d=Date.now()}=i;if("1"===process.env.VIBECLI_DISABLE_CLIENT_CONFIG_FETCH)return a=g(),a;const h=clientConfigSite(),m=o(),p=m&&m.site===h?m:null;if(!f&&p&&d-p.fetchedAt<3e5)return a={config:p.config,source:"cache",revision:p.config.revision,fetchedAt:p.fetchedAt},a;const C=p?.config??("vibeapi"===h?t():null),v=new AbortController,b=setTimeout(()=>v.abort(),l);try{const t={};p?.etag&&(t["If-None-Match"]=p.etag);const o=await u(`${c.getBaseUrl()}/api/platform/vibecode/config`,{method:"GET",headers:t,signal:v.signal});if(304===o.status&&p)return r({...p,fetchedAt:d}),a={config:p.config,source:"cloud",revision:p.config.revision,fetchedAt:d},a;if(!o.ok)return a=g(`HTTP ${o.status}`),a;const i=await o.json(),{config:f,problem:l}=n(i?.data,C);if(!f)return e.warn(`Gateway client config refused: ${l}`),a=g(`refused: ${l}`),a;l&&e.warn(`Gateway client config: ${l}`);const m=o.headers.get("etag")??void 0;return r({site:h,fetchedAt:d,config:f,...m?{etag:m}:{}}),s(),a={config:f,source:"cloud",revision:f.revision,fetchedAt:d,...l?{problem:l}:{}},a}catch(t){return e.logError("refreshClientConfig",t),a=g(t instanceof Error?t.message:String(t)),a}finally{clearTimeout(b)}}
@@ -73,7 +73,12 @@ export declare function readCachedClientConfig(): CachedClientConfig | null;
73
73
  export declare function writeCachedClientConfig(entry: CachedClientConfig): void;
74
74
  /** The snapshot shipped with the package (production config at release time). */
75
75
  export declare function bundledClientConfig(): ClientConfig | null;
76
- /** The config in effect without touching the network: cache, else the bundled snapshot. */
76
+ export declare function setClientConfigSiteResolver(resolver: (() => string) | null): void;
77
+ /**
78
+ * The config in effect without touching the network: the cache when it came from the current
79
+ * gateway's site, else the bundled snapshot. A cache from another gateway (the user switched
80
+ * addresses) never applies, and without a resolver the cache is not trusted at all.
81
+ */
77
82
  export declare function currentClientConfig(): {
78
83
  config: ClientConfig;
79
84
  source: ClientConfigSource;
@@ -1 +1 @@
1
- import{createHash as e,randomUUID as t}from"crypto";import{existsSync as n,mkdirSync as i,readFileSync as o,renameSync as r,writeFileSync as s}from"fs";import{homedir as l}from"os";import{dirname as c,join as f}from"path";import{fileURLToPath as a}from"url";export const CLIENT_CONFIG_SCHEMA=1;const u=new Set(["haiku","sonnet","opus","fable"]),d=/^[A-Za-z0-9._:@/\-[\]]{1,200}$/,m=/^[a-z][a-z0-9-]{0,31}$/,p=/^\d+(\.\d+){0,3}$/,b=e=>!!e&&"object"==typeof e&&!Array.isArray(e),h=e=>"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0;function g(e){if(!b(e)||"string"!=typeof e.id||!e.id.trim())return null;const t={id:e.id.trim()};if(!0===e.hidden)return{...t,hidden:!0};"string"==typeof e.name&&e.name.trim()&&(t.name=e.name.trim()),"string"==typeof e.description&&e.description.trim()&&(t.description=e.description.trim());const n=h(e.context_window);n&&(t.contextWindow=n);const i=h(e.auto_compact_tokens);if(i&&(t.autoCompactTokens=i),b(e.clients)){const n={};for(const[t,i]of Object.entries(e.clients))m.test(t)&&"boolean"==typeof i&&(n[t]=i);Object.keys(n).length>0&&(t.clients=n)}return"string"==typeof e.min_vibecli_version&&p.test(e.min_vibecli_version)&&(t.minVibecliVersion=e.min_vibecli_version),"number"==typeof e.rollout_percent&&e.rollout_percent>=0&&e.rollout_percent<=100&&(t.rolloutPercent=e.rollout_percent),t}function _(e,t,n,i){if(void 0===e)return{};if(!b(e))throw new Error(`vibecli.${i} must be an object`);const o={};for(const[r,s]of Object.entries(e)){if(!t.test(r)||"string"!=typeof s||!n(s))throw new Error(`vibecli.${i}.${r} is invalid`);o[r]=s}return o}function v(e,t,{nonEmpty:n=!1}={}){if(void 0===e)return[];if(!Array.isArray(e)||e.some(e=>"string"!=typeof e||!d.test(e)))throw new Error(`vibecli.${t} must be a list of model ids`);if(n&&0===e.length)throw new Error(`vibecli.${t} must not be empty`);return[...e]}function y(e,t,n){if(void 0===e)return{};if(!b(e))throw new Error(`vibecli.${t} must be an object`);const i={};for(const[o,r]of Object.entries(e)){if(!u.has(o))throw new Error(`vibecli.${t}.${o} is not a tier slot`);i[o]=v(r,`${t}.${o}`,{nonEmpty:n})}return i}const C=e=>(e??[]).filter(e=>!e.hidden).length;export function parseClientConfig(e,t){if(!b(e))return{config:null,problem:"not an object"};if(1!==e.schema)return{config:null,problem:`unsupported schema ${String(e.schema)}`};if(!b(e.models))return{config:null,problem:"models is not an object"};const n={};for(const[t,i]of Object.entries(e.models)){if(!Array.isArray(i))return{config:null,problem:`models.${t} is not a list`};const e=i.map(g);if(e.some(e=>null===e))return{config:null,problem:`models.${t} has a row without an id`};n[t]=e}let i,o;try{i=function(e){if(null==e)return;if(!b(e))throw new Error("vibecli must be an object");const t={};if(void 0!==e.min_version){if("string"!=typeof e.min_version||e.min_version&&!p.test(e.min_version))throw new Error("vibecli.min_version is invalid");e.min_version&&(t.minVersion=e.min_version)}const n=_(e.default_models,/^(haiku|sonnet|opus|fable)$/,e=>d.test(e),"default_models");Object.keys(n).length&&(t.defaultModels=n);const i=y(e.retired_default_models,"retired_default_models",!1);Object.keys(i).length&&(t.retiredDefaultModels=i);const o=_(e.tool_defaults,m,e=>""===e||d.test(e),"tool_defaults");Object.keys(o).length&&(t.toolDefaults=o);const r=y(e.tier_chains,"tier_chains",!0);Object.keys(r).length&&(t.tierChains=r);const s=v(e.retired_models,"retired_models");s.length&&(t.retiredModels=s);const l=_(e.tool_min_versions,m,e=>""===e||p.test(e),"tool_min_versions");Object.keys(l).length&&(t.toolMinVersions=l);const c=v(e.agy_models,"agy_models");c.length&&(t.agyModels=c);const f=v(e.one_million_fallback,"one_million_fallback");return f.length&&(t.oneMillionFallback=f),!0===e.accept_shrink&&(t.acceptShrink=!0),t}(e.vibecli)}catch(e){o=`vibecli section dropped: ${e instanceof Error?e.message:String(e)}`}if(t&&(!b(e.vibecli)||!0!==e.vibecli.accept_shrink))for(const[e,i]of Object.entries(t.models)){const t=C(i),o=C(n[e]);if(t>0&&0===o||t>=4&&2*o<t)return{config:null,problem:`models.${e} shrank from ${t} to ${o}`}}return{config:{schema:1,revision:"string"==typeof e.revision?e.revision:"",models:n,...i?{vibecli:i}:{}},problem:o}}export function serializeClientConfig(e){const t=Object.fromEntries(Object.entries(e.models).map(([e,t])=>[e,t.map(e=>({id:e.id,...e.hidden?{hidden:!0}:{},...e.name?{name:e.name}:{},...e.description?{description:e.description}:{},...e.contextWindow?{context_window:e.contextWindow}:{},...e.autoCompactTokens?{auto_compact_tokens:e.autoCompactTokens}:{},...e.clients?{clients:e.clients}:{},...e.minVibecliVersion?{min_vibecli_version:e.minVibecliVersion}:{},...void 0!==e.rolloutPercent?{rollout_percent:e.rolloutPercent}:{}}))])),n=e.vibecli,i=n?{...n.minVersion?{min_version:n.minVersion}:{},...n.defaultModels?{default_models:n.defaultModels}:{},...n.retiredDefaultModels?{retired_default_models:n.retiredDefaultModels}:{},...n.toolDefaults?{tool_defaults:n.toolDefaults}:{},...n.tierChains?{tier_chains:n.tierChains}:{},...n.retiredModels?{retired_models:n.retiredModels}:{},...n.toolMinVersions?{tool_min_versions:n.toolMinVersions}:{},...n.agyModels?{agy_models:n.agyModels}:{},...n.oneMillionFallback?{one_million_fallback:n.oneMillionFallback}:{},...n.acceptShrink?{accept_shrink:!0}:{}}:void 0;return{schema:e.schema,revision:e.revision,models:t,...i?{vibecli:i}:{}}}function k(){const e=process.env.VIBECLI_CONFIG_DIR?.trim();if(e)return e;const t=process.env.VIBECLI_TEST_HOME?.trim();return f(t||l(),".vibecli")}export const cachePath=()=>f(k(),"client-config.json");function w(e,t){i(c(e),{recursive:!0});const n=`${e}.${process.pid}.tmp`;s(n,t,"utf-8"),r(n,e)}export function readCachedClientConfig(){try{if(!n(cachePath()))return null;const e=JSON.parse(o(cachePath(),"utf-8"));if("string"!=typeof e.site||"number"!=typeof e.fetchedAt)return null;const{config:t}=parseClientConfig(e.config);return t?{site:e.site,fetchedAt:e.fetchedAt,config:t,..."string"==typeof e.etag?{etag:e.etag}:{}}:null}catch{return null}}export function writeCachedClientConfig(e){w(cachePath(),JSON.stringify({site:e.site,etag:e.etag,fetchedAt:e.fetchedAt,config:serializeClientConfig(e.config)},null,2)+"\n")}let j;export function bundledClientConfig(){if("1"===process.env.VIBECLI_NO_BUNDLED_CLIENT_CONFIG)return null;if(void 0!==j)return j;j=null;const e=c(a(import.meta.url));for(const t of[f(e,"..","..","client-config.snapshot.json"),f(e,"..","client-config.snapshot.json")])try{if(!n(t))continue;j=parseClientConfig(JSON.parse(o(t,"utf-8"))).config;break}catch{}return j}export function currentClientConfig(){const e=readCachedClientConfig();if(e)return{config:e.config,source:"cache",fetchedAt:e.fetchedAt};const t=bundledClientConfig();return t?{config:t,source:"bundled"}:null}let E=null,V=null;export function setClientIdentityForTests(e,t){E=e,V=t}export const clientVersion=()=>E??function(){try{const e=c(a(import.meta.url));for(const t of[f(e,"..","..","package.json"),f(e,"..","package.json")])if(n(t))return String(JSON.parse(o(t,"utf-8")).version??"0.0.0")}catch{}return"0.0.0"}();function $(e,t){const n=e.split(".").map(e=>parseInt(e,10)||0),i=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(n.length,i.length);e++){const t=(n[e]??0)-(i[e]??0);if(t)return t}return 0}export function installId(){if(V)return V;const e=f(k(),"install-id");try{if(n(e)){const t=o(e,"utf-8").trim();if(t)return t}const i=t();return w(e,i+"\n"),i}catch{return"unknown"}}export function rolloutBucket(t){return e("sha256").update(`${installId()}:${t}`).digest().readUInt32BE(0)%100}export function isEligible(e){return!(e.minVibecliVersion&&$(clientVersion(),e.minVibecliVersion)<0||void 0!==e.rolloutPercent&&rolloutBucket(e.id)>=e.rolloutPercent)}export function eligibleLists(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t.map(e=>e.hidden||isEligible(e)?e:{id:e.id,hidden:!0})]))}export function usableVibecliSection(e){const t=e?.vibecli;if(t&&!(t.minVersion&&$(clientVersion(),t.minVersion)<0))return t}
1
+ import{createHash as e,randomUUID as t}from"crypto";import{existsSync as n,mkdirSync as i,readFileSync as o,renameSync as r,writeFileSync as s}from"fs";import{homedir as l}from"os";import{dirname as c,join as f}from"path";import{fileURLToPath as a}from"url";export const CLIENT_CONFIG_SCHEMA=1;const u=new Set(["haiku","sonnet","opus","reasoning","fable"]),d=/^[A-Za-z0-9._:@/\-[\]]{1,200}$/,m=/^[a-z][a-z0-9-]{0,31}$/,p=/^\d+(\.\d+){0,3}$/,h=e=>!!e&&"object"==typeof e&&!Array.isArray(e),b=e=>"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0;function g(e){if(!h(e)||"string"!=typeof e.id||!e.id.trim())return null;const t={id:e.id.trim()};if(!0===e.hidden)return{...t,hidden:!0};"string"==typeof e.name&&e.name.trim()&&(t.name=e.name.trim()),"string"==typeof e.description&&e.description.trim()&&(t.description=e.description.trim());const n=b(e.context_window);n&&(t.contextWindow=n);const i=b(e.auto_compact_tokens);if(i&&(t.autoCompactTokens=i),h(e.clients)){const n={};for(const[t,i]of Object.entries(e.clients))m.test(t)&&"boolean"==typeof i&&(n[t]=i);Object.keys(n).length>0&&(t.clients=n)}return"string"==typeof e.min_vibecli_version&&p.test(e.min_vibecli_version)&&(t.minVibecliVersion=e.min_vibecli_version),"number"==typeof e.rollout_percent&&e.rollout_percent>=0&&e.rollout_percent<=100&&(t.rolloutPercent=e.rollout_percent),t}function _(e,t,n,i){if(void 0===e)return{};if(!h(e))throw new Error(`vibecli.${i} must be an object`);const o={};for(const[r,s]of Object.entries(e)){if(!t.test(r)||"string"!=typeof s||!n(s))throw new Error(`vibecli.${i}.${r} is invalid`);o[r]=s}return o}function v(e,t,{nonEmpty:n=!1}={}){if(void 0===e)return[];if(!Array.isArray(e)||e.some(e=>"string"!=typeof e||!d.test(e)))throw new Error(`vibecli.${t} must be a list of model ids`);if(n&&0===e.length)throw new Error(`vibecli.${t} must not be empty`);return[...e]}function y(e,t,n){if(void 0===e)return{};if(!h(e))throw new Error(`vibecli.${t} must be an object`);const i={};for(const[o,r]of Object.entries(e)){if(!u.has(o))throw new Error(`vibecli.${t}.${o} is not a tier slot`);i[o]=v(r,`${t}.${o}`,{nonEmpty:n})}return i}const C=e=>(e??[]).filter(e=>!e.hidden).length;export function parseClientConfig(e,t){if(!h(e))return{config:null,problem:"not an object"};if(1!==e.schema)return{config:null,problem:`unsupported schema ${String(e.schema)}`};if(!h(e.models))return{config:null,problem:"models is not an object"};const n={};for(const[t,i]of Object.entries(e.models)){if(!Array.isArray(i))return{config:null,problem:`models.${t} is not a list`};const e=i.map(g);if(e.some(e=>null===e))return{config:null,problem:`models.${t} has a row without an id`};n[t]=e}let i,o;try{i=function(e){if(null==e)return;if(!h(e))throw new Error("vibecli must be an object");const t={};if(void 0!==e.min_version){if("string"!=typeof e.min_version||e.min_version&&!p.test(e.min_version))throw new Error("vibecli.min_version is invalid");e.min_version&&(t.minVersion=e.min_version)}const n=_(e.default_models,/^(haiku|sonnet|opus|reasoning|fable)$/,e=>d.test(e),"default_models");Object.keys(n).length&&(t.defaultModels=n);const i=y(e.retired_default_models,"retired_default_models",!1);Object.keys(i).length&&(t.retiredDefaultModels=i);const o=_(e.tool_defaults,m,e=>""===e||d.test(e),"tool_defaults");Object.keys(o).length&&(t.toolDefaults=o);const r=y(e.tier_chains,"tier_chains",!0);Object.keys(r).length&&(t.tierChains=r);const s=v(e.retired_models,"retired_models");s.length&&(t.retiredModels=s);const l=_(e.tool_min_versions,m,e=>""===e||p.test(e),"tool_min_versions");Object.keys(l).length&&(t.toolMinVersions=l);const c=v(e.agy_models,"agy_models");c.length&&(t.agyModels=c);const f=v(e.one_million_fallback,"one_million_fallback");return f.length&&(t.oneMillionFallback=f),!0===e.accept_shrink&&(t.acceptShrink=!0),t}(e.vibecli)}catch(e){o=`vibecli section dropped: ${e instanceof Error?e.message:String(e)}`}if(t&&(!h(e.vibecli)||!0!==e.vibecli.accept_shrink))for(const[e,i]of Object.entries(t.models)){const t=C(i),o=C(n[e]);if(t>0&&0===o||t>=4&&2*o<t)return{config:null,problem:`models.${e} shrank from ${t} to ${o}`}}return{config:{schema:1,revision:"string"==typeof e.revision?e.revision:"",models:n,...i?{vibecli:i}:{}},problem:o}}export function serializeClientConfig(e){const t=Object.fromEntries(Object.entries(e.models).map(([e,t])=>[e,t.map(e=>({id:e.id,...e.hidden?{hidden:!0}:{},...e.name?{name:e.name}:{},...e.description?{description:e.description}:{},...e.contextWindow?{context_window:e.contextWindow}:{},...e.autoCompactTokens?{auto_compact_tokens:e.autoCompactTokens}:{},...e.clients?{clients:e.clients}:{},...e.minVibecliVersion?{min_vibecli_version:e.minVibecliVersion}:{},...void 0!==e.rolloutPercent?{rollout_percent:e.rolloutPercent}:{}}))])),n=e.vibecli,i=n?{...n.minVersion?{min_version:n.minVersion}:{},...n.defaultModels?{default_models:n.defaultModels}:{},...n.retiredDefaultModels?{retired_default_models:n.retiredDefaultModels}:{},...n.toolDefaults?{tool_defaults:n.toolDefaults}:{},...n.tierChains?{tier_chains:n.tierChains}:{},...n.retiredModels?{retired_models:n.retiredModels}:{},...n.toolMinVersions?{tool_min_versions:n.toolMinVersions}:{},...n.agyModels?{agy_models:n.agyModels}:{},...n.oneMillionFallback?{one_million_fallback:n.oneMillionFallback}:{},...n.acceptShrink?{accept_shrink:!0}:{}}:void 0;return{schema:e.schema,revision:e.revision,models:t,...i?{vibecli:i}:{}}}function k(){const e=process.env.VIBECLI_CONFIG_DIR?.trim();if(e)return e;const t=process.env.VIBECLI_TEST_HOME?.trim();return f(t||l(),".vibecli")}export const cachePath=()=>f(k(),"client-config.json");function w(e,t){i(c(e),{recursive:!0});const n=`${e}.${process.pid}.tmp`;s(n,t,"utf-8"),r(n,e)}export function readCachedClientConfig(){try{if(!n(cachePath()))return null;const e=JSON.parse(o(cachePath(),"utf-8"));if("string"!=typeof e.site||"number"!=typeof e.fetchedAt)return null;const{config:t}=parseClientConfig(e.config);return t?{site:e.site,fetchedAt:e.fetchedAt,config:t,..."string"==typeof e.etag?{etag:e.etag}:{}}:null}catch{return null}}export function writeCachedClientConfig(e){w(cachePath(),JSON.stringify({site:e.site,etag:e.etag,fetchedAt:e.fetchedAt,config:serializeClientConfig(e.config)},null,2)+"\n")}let j;export function bundledClientConfig(){if("1"===process.env.VIBECLI_NO_BUNDLED_CLIENT_CONFIG)return null;if(void 0!==j)return j;j=null;const e=c(a(import.meta.url));for(const t of[f(e,"..","..","client-config.snapshot.json"),f(e,"..","client-config.snapshot.json")])try{if(!n(t))continue;j=parseClientConfig(JSON.parse(o(t,"utf-8"))).config;break}catch{}return j}let E=null;export function setClientConfigSiteResolver(e){E=e}export function currentClientConfig(){const e=readCachedClientConfig();let t=null;try{t=E?E():null}catch{t=null}if(e&&null!==t&&e.site===t)return{config:e.config,source:"cache",fetchedAt:e.fetchedAt};const n=bundledClientConfig();return n?{config:n,source:"bundled"}:null}let V=null,$=null;export function setClientIdentityForTests(e,t){V=e,$=t}export const clientVersion=()=>V??function(){try{const e=c(a(import.meta.url));for(const t of[f(e,"..","..","package.json"),f(e,"..","package.json")])if(n(t))return String(JSON.parse(o(t,"utf-8")).version??"0.0.0")}catch{}return"0.0.0"}();function O(e,t){const n=e.split(".").map(e=>parseInt(e,10)||0),i=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(n.length,i.length);e++){const t=(n[e]??0)-(i[e]??0);if(t)return t}return 0}export function installId(){if($)return $;const e=f(k(),"install-id");try{if(n(e)){const t=o(e,"utf-8").trim();if(t)return t}const i=t();return w(e,i+"\n"),i}catch{return"unknown"}}export function rolloutBucket(t){return e("sha256").update(`${installId()}:${t}`).digest().readUInt32BE(0)%100}export function isEligible(e){return!(e.minVibecliVersion&&O(clientVersion(),e.minVibecliVersion)<0||void 0!==e.rolloutPercent&&rolloutBucket(e.id)>=e.rolloutPercent)}export function eligibleLists(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t.map(e=>e.hidden||isEligible(e)?e:{id:e.id,hidden:!0})]))}export function usableVibecliSection(e){const t=e?.vibecli;if(t&&!(t.minVersion&&O(clientVersion(),t.minVersion)<0))return t}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/api-helper",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
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",