@vibeapi/api-helper 0.0.96 → 0.0.97

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.
Files changed (60) hide show
  1. package/client-config.snapshot.json +123 -10
  2. package/dist/brand.json +76 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/client-config.snapshot.json +123 -10
  5. package/dist/commands/base.js +1 -1
  6. package/dist/commands/completion.js +1 -1
  7. package/dist/commands/setup.d.ts +2 -0
  8. package/dist/commands/setup.js +1 -1
  9. package/dist/commands/update.d.ts +2 -1
  10. package/dist/commands/update.js +1 -1
  11. package/dist/lib/api-validator.js +1 -1
  12. package/dist/lib/auto-update.js +1 -1
  13. package/dist/lib/brand.d.ts +82 -8
  14. package/dist/lib/brand.js +1 -1
  15. package/dist/lib/cli-help.d.ts +1 -1
  16. package/dist/lib/cli-help.js +1 -1
  17. package/dist/lib/client-config-sync.js +1 -1
  18. package/dist/lib/client-config.d.ts +5 -4
  19. package/dist/lib/client-config.js +1 -1
  20. package/dist/lib/codex-sessions.js +1 -1
  21. package/dist/lib/command-docs.js +1 -1
  22. package/dist/lib/command.js +1 -1
  23. package/dist/lib/config.d.ts +1 -1
  24. package/dist/lib/config.js +1 -1
  25. package/dist/lib/errors.d.ts +10 -10
  26. package/dist/lib/errors.js +1 -1
  27. package/dist/lib/gateway-models.js +1 -1
  28. package/dist/lib/gateway-protocol.d.ts +13 -0
  29. package/dist/lib/gateway-protocol.js +1 -0
  30. package/dist/lib/i18n.js +1 -1
  31. package/dist/lib/model-refresh.js +1 -1
  32. package/dist/lib/model-registry.d.ts +2 -4
  33. package/dist/lib/model-registry.js +1 -1
  34. package/dist/lib/persistent-env.js +1 -1
  35. package/dist/lib/program.js +1 -1
  36. package/dist/lib/secret-store.js +1 -1
  37. package/dist/lib/tool-manager.d.ts +8 -0
  38. package/dist/lib/tool-manager.js +1 -1
  39. package/dist/lib/tools/antigravity.js +1 -1
  40. package/dist/lib/tools/claude-code.js +1 -1
  41. package/dist/lib/tools/claude-desktop.js +1 -1
  42. package/dist/lib/tools/claude-plugins.d.ts +8 -13
  43. package/dist/lib/tools/claude-plugins.js +1 -1
  44. package/dist/lib/tools/codex-catalog.d.ts +1 -1
  45. package/dist/lib/tools/codex-catalog.js +1 -1
  46. package/dist/lib/tools/codex.js +1 -1
  47. package/dist/lib/tools/elevated-reg.js +1 -1
  48. package/dist/lib/tools/grok.js +1 -1
  49. package/dist/lib/tools/openclaw.js +1 -1
  50. package/dist/lib/tools/tool-installs.d.ts +2 -2
  51. package/dist/lib/tools/tool-installs.js +1 -1
  52. package/dist/lib/tools/types.js +1 -1
  53. package/dist/lib/windows-env.js +1 -1
  54. package/dist/lib/wizard.js +1 -1
  55. package/dist/locales/en_US.json +105 -97
  56. package/dist/locales/zh_CN.json +105 -97
  57. package/dist/models.json +1 -27
  58. package/dist/utils/logger.js +1 -1
  59. package/models.json +1 -27
  60. package/package.json +2 -1
@@ -1 +1 @@
1
- import{logger as e}from"../utils/logger.js";import{configManager as r}from"./config.js";import{i18n as t}from"./i18n.js";import{rememberPublishedAddresses as o}from"./gateway-addresses.js";import{eligibleLists as a}from"./client-config.js";import{refreshClientConfig as n}from"./client-config-sync.js";const s=e=>new Promise(r=>setTimeout(r,e));async function i(e,o,a){const n=`${r.getBaseUrl()}/v1/models`,s=new AbortController,i=setTimeout(()=>s.abort(),o);try{const r=await a(n,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:s.signal});if(401===r.status)return{valid:!1,error:"invalid_api_key",message:"API Key is invalid or expired"};if(r.ok){try{const e=await r.json();if(e&&"list"===e.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${r.status}: ${r.statusText}`}}catch(e){return e instanceof Error&&"AbortError"===e.name?{valid:!1,error:"network_error",message:"Request timeout"}:function(e){const r=e?.cause?.code;return"string"==typeof r&&l.has(r)}(e)?{valid:!1,error:"network_error",message:t.t("messages.certificate_intercepted",{url:n})}:{valid:!1,error:"network_error",message:e instanceof Error?e.message:"Network connection failed"}}finally{clearTimeout(i)}}const l=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(t,o={}){const{timeoutMs:a=3e4,fetchFn:n=fetch}=o,s=`${r.getBaseUrl()}/v1/models`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const e=await n(s,{method:"GET",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},signal:i.signal});if(!e.ok)return{ok:!1,models:[],error:`HTTP ${e.status}`};const r=await e.json();return{ok:!0,models:(Array.isArray(r?.data)?r.data:[]).map(e=>"string"==typeof e?e:e?.id).filter(e=>"string"==typeof e&&e.trim().length>0).map(e=>e.trim())}}catch(r){return e.logError("fetchModels",r),{ok:!1,models:[],error:r instanceof Error?r.message:"network error"}}finally{clearTimeout(l)}}function c(e){return e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.name).map(e=>({name:e.name.trim(),..."string"==typeof e.labelOverride?{labelOverride:e.labelOverride}:{},..."boolean"==typeof e.supports1m?{supports1m:e.supports1m}:{}})).filter(e=>e.name.length>0)}export async function fetchGatewayStatus(t={}){const{timeoutMs:a=15e3,fetchFn:n=fetch}=t,s=`${r.getBaseUrl()}/api/status`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const e=await n(s,{method:"GET",signal:i.signal});if(!e.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${e.status}`};const t=await e.json();o(t?.data,r.getBaseUrl());let a=t?.data?.claude_desktop_group_models;if("string"==typeof a)try{a=JSON.parse(a)}catch{a=void 0}const l={};if(a&&"object"==typeof a&&!Array.isArray(a))for(const[e,r]of Object.entries(a))Array.isArray(r)&&(l[e]=c(r));return{ok:!0,claudeDesktopGroupModels:l}}catch(r){return e.logError("fetchGatewayStatus",r),{ok:!1,claudeDesktopGroupModels:{},error:r instanceof Error?r.message:"network error"}}finally{clearTimeout(l)}}export async function fetchKeyGroupInfo(t,o={}){const{timeoutMs:a=1e4,fetchFn:n=fetch}=o,s=`${r.getBaseUrl()}/api/platform/vibecode/key`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const e=await n(s,{method:"GET",headers:{Authorization:`Bearer ${t}`},signal:i.signal});if(!e.ok)return null;const r=await e.json(),o=r?.data;if(!o||"string"!=typeof o.group||!Array.isArray(o.claude_desktop_models))return null;const a=Array.isArray(o.groups)?o.groups.filter(e=>"string"==typeof e&&!!e):[];return{group:o.group,groups:a.length>0?a:[o.group],claudeDesktopModels:c(o.claude_desktop_models)}}catch(r){return e.logError("fetchKeyGroupInfo",r),null}finally{clearTimeout(l)}}export async function fetchClientModelConfig(e={}){const r=await n(e);return r.config?a(r.config.models):null}export async function validateApiKey(r,t={}){const{timeoutMs:o=3e4,retries:a=2,backoffMs:n=500,fetchFn:l=fetch,sleepFn:c=s}=t;let u={valid:!1,error:"network_error",message:"Network connection failed"};for(let t=0;t<=a;t++){const s=await i(r,o,l);if(s.valid||"invalid_api_key"===s.error)return s.valid||e.logError("validateApiKey",new Error(s.message||"invalid_api_key")),s;u=s,t<a&&await c(n*Math.pow(2,t))}return e.logError("validateApiKey",new Error(u.message||"network_error")),u}
1
+ import{KEY_INFO_PATH as e}from"./gateway-protocol.js";import{logger as r}from"../utils/logger.js";import{configManager as t}from"./config.js";import{i18n as o}from"./i18n.js";import{rememberPublishedAddresses as a}from"./gateway-addresses.js";import{eligibleLists as n}from"./client-config.js";import{refreshClientConfig as s}from"./client-config-sync.js";const i=e=>new Promise(r=>setTimeout(r,e));async function l(e,r,a){const n=`${t.getBaseUrl()}/v1/models`,s=new AbortController,i=setTimeout(()=>s.abort(),r);try{const r=await a(n,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:s.signal});if(401===r.status)return{valid:!1,error:"invalid_api_key",message:"API Key is invalid or expired"};if(r.ok){try{const e=await r.json();if(e&&"list"===e.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${r.status}: ${r.statusText}`}}catch(e){return e instanceof Error&&"AbortError"===e.name?{valid:!1,error:"network_error",message:"Request timeout"}:function(e){const r=e?.cause?.code;return"string"==typeof r&&c.has(r)}(e)?{valid:!1,error:"network_error",message:o.t("messages.certificate_intercepted",{url:n})}:{valid:!1,error:"network_error",message:e instanceof Error?e.message:"Network connection failed"}}finally{clearTimeout(i)}}const c=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(e,o={}){const{timeoutMs:a=3e4,fetchFn:n=fetch}=o,s=`${t.getBaseUrl()}/v1/models`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const r=await n(s,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:i.signal});if(!r.ok)return{ok:!1,models:[],error:`HTTP ${r.status}`};const t=await r.json();return{ok:!0,models:(Array.isArray(t?.data)?t.data:[]).map(e=>"string"==typeof e?e:e?.id).filter(e=>"string"==typeof e&&e.trim().length>0).map(e=>e.trim())}}catch(e){return r.logError("fetchModels",e),{ok:!1,models:[],error:e instanceof Error?e.message:"network error"}}finally{clearTimeout(l)}}function u(e){return e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.name).map(e=>({name:e.name.trim(),..."string"==typeof e.labelOverride?{labelOverride:e.labelOverride}:{},..."boolean"==typeof e.supports1m?{supports1m:e.supports1m}:{}})).filter(e=>e.name.length>0)}export async function fetchGatewayStatus(e={}){const{timeoutMs:o=15e3,fetchFn:n=fetch}=e,s=`${t.getBaseUrl()}/api/status`,i=new AbortController,l=setTimeout(()=>i.abort(),o);try{const e=await n(s,{method:"GET",signal:i.signal});if(!e.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${e.status}`};const r=await e.json();a(r?.data,t.getBaseUrl());let o=r?.data?.claude_desktop_group_models;if("string"==typeof o)try{o=JSON.parse(o)}catch{o=void 0}const l={};if(o&&"object"==typeof o&&!Array.isArray(o))for(const[e,r]of Object.entries(o))Array.isArray(r)&&(l[e]=u(r));return{ok:!0,claudeDesktopGroupModels:l}}catch(e){return r.logError("fetchGatewayStatus",e),{ok:!1,claudeDesktopGroupModels:{},error:e instanceof Error?e.message:"network error"}}finally{clearTimeout(l)}}export async function fetchKeyGroupInfo(o,a={}){const{timeoutMs:n=1e4,fetchFn:s=fetch}=a,i=`${t.getBaseUrl()}${e}`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await s(i,{method:"GET",headers:{Authorization:`Bearer ${o}`},signal:l.signal});if(!e.ok)return null;const r=await e.json(),t=r?.data;if(!t||"string"!=typeof t.group||!Array.isArray(t.claude_desktop_models))return null;const a=Array.isArray(t.groups)?t.groups.filter(e=>"string"==typeof e&&!!e):[];return{group:t.group,groups:a.length>0?a:[t.group],claudeDesktopModels:u(t.claude_desktop_models)}}catch(e){return r.logError("fetchKeyGroupInfo",e),null}finally{clearTimeout(c)}}export async function fetchClientModelConfig(e={}){const r=await s(e);return r.config?n(r.config.models):null}export async function validateApiKey(e,t={}){const{timeoutMs:o=3e4,retries:a=2,backoffMs:n=500,fetchFn:s=fetch,sleepFn:c=i}=t;let u={valid:!1,error:"network_error",message:"Network connection failed"};for(let t=0;t<=a;t++){const i=await l(e,o,s);if(i.valid||"invalid_api_key"===i.error)return i.valid||r.logError("validateApiKey",new Error(i.message||"invalid_api_key")),i;u=i,t<a&&await c(n*Math.pow(2,t))}return r.logError("validateApiKey",new Error(u.message||"network_error")),u}
@@ -1 +1 @@
1
- import{chmodSync as e,existsSync as t,mkdirSync as r,readFileSync as n,renameSync as o,writeFileSync as s}from"fs";import{homedir as a}from"os";import{dirname as l,join as i,sep as u}from"path";import{spawnSync as c}from"child_process";import p from"chalk";import{checkForUpdate as d,compareSemver as m,readLocalPackage as f,UPDATE_SOURCES as _}from"../commands/update.js";import{i18n as h}from"./i18n.js";import{isColorEnabled as g}from"./runtime-options.js";import{logger as x}from"../utils/logger.js";import{isHelpRequest as v}from"./cli-help.js";export const UPDATE_CHECK_INTERVAL_MS=216e5;export const INSTALL_RETRY_INTERVAL_MS=36e5;export const INSTALL_TIMEOUT_MS=45e3;function I(e,t){return g()?e(t):t}export function resolveUpdateCachePath(e=process.env){const t=e.VIBECLI_CONFIG_DIR?.trim();if(t)return i(t,"update-state.json");const r=e.VIBECLI_TEST_HOME?.trim();return i(r||a(),".vibecli","update-state.json")}export function isGlobalPackageInstall(e){return e.split(u).includes("node_modules")}export function isNpxExecution(e=process.env){return"exec"===e.npm_command||"npx"===e.npm_lifecycle_event}export function isPnpmGlobalInstall(e){return e.includes(`${u}.pnpm${u}`)||e.includes(`${u}pnpm${u}global${u}`)}export function resolveNpmGlobalPrefix(e){const t=`${u}node_modules${u}`,r=e.indexOf(t);if(r<0)return null;const n=e.slice(0,r);return n.endsWith(`${u}lib`)?l(n):n}export function shouldSkipStartupUpdate(e,t=process.env){return"1"===t.VIBECLI_SKIP_AUTO_UPDATE||"1"===t.VIBECLI_DISABLE_AUTO_UPDATE||(!(!["--json","--non-interactive","--dry-run","--help","-h","--version","-v"].some(t=>e.includes(t))&&!v(e))||e.includes("update")||e.includes("completion"))}function y(t,n,a,i,u){try{r(l(t),{recursive:!0,mode:448});const c=`${t}.tmp-${process.pid}`,p={package_name:n,checked_at:a,latest:i.latest,source:i.source,registry:i.registry,errors:i.errors,...void 0===u?{}:{install_attempted_at:u,install_attempted_version:i.latest||void 0}};s(c,JSON.stringify(p),{encoding:"utf-8",mode:384}),o(c,t),e(t,384)}catch(e){x.warn("Failed to persist update check cache:",e)}}const E=(e,t)=>c(e,t,{stdio:"inherit",timeout:45e3,killSignal:"SIGTERM"}),k=(e,t)=>c(process.execPath,[process.argv[1],...e],{stdio:"inherit",env:t});export async function runStartupUpdate(e,r={}){const o=r.env||process.env,s=r.localPackage||f(),a=r.globalInstall??isGlobalPackageInstall(s.root),l=r.npx??isNpxExecution(o);if(!a||l||shouldSkipStartupUpdate(e,o))return{status:"skipped",handled:!1,source:null};const i=r.now??Date.now(),u=r.cachePath||resolveUpdateCachePath(o),c=function(e,r,o){try{if(!t(e))return null;const s=JSON.parse(n(e,"utf-8"));if(s.package_name!==r.name||!Number.isFinite(s.checked_at))return null;const a=s.latest?216e5:6e5;return o-s.checked_at>=a?null:{result:{current:r.version,latest:s.latest,up_to_date:s.latest?m(r.version,s.latest)>=0:null,source:s.source,registry:s.registry,errors:Array.isArray(s.errors)?s.errors:[],error:s.latest?null:(s.errors||[]).map(e=>`${e.source}: ${e.error}`).join("; ")||"unknown"},installAttemptedAt:s.latest&&s.install_attempted_version===s.latest&&Number.isFinite(s.install_attempted_at)?s.install_attempted_at:null}}catch{return null}}(u,s,i);let g=c?.result,x=c?.installAttemptedAt||null;if(g||(g=await d({localPackage:s,fetchFn:r.fetchFn}),y(u,s.name,i,g),x=null),!g.latest)return{status:"unavailable",handled:!1,source:null};if(g.up_to_date)return{status:"current",handled:!1,source:g.source};if(null!==x&&i-x<36e5)return{status:"update_failed",handled:!1,source:g.source};const v=r.output||console.log,A=r.errorOutput||console.error,P=r.installRunner||E,S=isPnpmGlobalInstall(s.root),T=S?"win32"===process.platform?"pnpm.cmd":"pnpm":"win32"===process.platform?"npm.cmd":"npm",$=S?null:resolveNpmGlobalPrefix(s.root);v(I(p.cyan,h.t("update.auto_installing",{version:g.latest})));let b=null,N="unknown";for(const e of _.map(e=>e.registry)){const t=P(T,S?["add","--global",`${s.name}@${g.latest}`,"--registry",e]:["install","--global",...$?["--prefix",$]:[],`${s.name}@${g.latest}`,"--registry",e,"--no-audit","--no-fund","--fetch-timeout=15000","--fetch-retries=1","--fetch-retry-mintimeout=1000","--fetch-retry-maxtimeout=3000"]);if(0===t.status){b=e;break}N=t.error?.message||`exit ${t.status??"unknown"}`}if(!b)return y(u,s.name,i,g,i),A(I(p.yellow,h.t("update.auto_failed",{error:N}))),{status:"update_failed",handled:!1,source:g.source};v(I(p.green,h.t("update.auto_installed",{version:g.latest})));const U=(r.reexecRunner||k)(e,{...o,VIBECLI_SKIP_AUTO_UPDATE:"1"});return U.error?(A(I(p.yellow,h.t("update.reexec_failed",{error:U.error.message}))),{status:"update_failed",handled:!1,source:g.source}):(process.exitCode=U.status??1,{status:"reexecuted",handled:!0,source:g.source})}
1
+ import{chmodSync as e,existsSync as t,mkdirSync as r,readFileSync as n,renameSync as o,writeFileSync as s}from"fs";import{homedir as a}from"os";import{dirname as l,join as i,sep as u}from"path";import{spawnSync as c}from"child_process";import p from"chalk";import{checkForUpdate as d,compareSemver as m,readLocalPackage as f,UPDATE_SOURCES as _}from"../commands/update.js";import{i18n as h}from"./i18n.js";import{isColorEnabled as g}from"./runtime-options.js";import{logger as x}from"../utils/logger.js";import{isHelpRequest as v}from"./cli-help.js";import{brand as y,brandEnvName as k}from"./brand.js";export const UPDATE_CHECK_INTERVAL_MS=216e5;export const INSTALL_RETRY_INTERVAL_MS=36e5;export const INSTALL_TIMEOUT_MS=45e3;function A(e,t){return g()?e(t):t}export function resolveUpdateCachePath(e=process.env){const t=e[k("CONFIG_DIR")]?.trim();if(t)return i(t,"update-state.json");const r=e[k("TEST_HOME")]?.trim();return i(r||a(),y().configDirName,"update-state.json")}export function isGlobalPackageInstall(e){return e.split(u).includes("node_modules")}export function isNpxExecution(e=process.env){return"exec"===e.npm_command||"npx"===e.npm_lifecycle_event}export function isPnpmGlobalInstall(e){return e.includes(`${u}.pnpm${u}`)||e.includes(`${u}pnpm${u}global${u}`)}export function resolveNpmGlobalPrefix(e){const t=`${u}node_modules${u}`,r=e.indexOf(t);if(r<0)return null;const n=e.slice(0,r);return n.endsWith(`${u}lib`)?l(n):n}export function shouldSkipStartupUpdate(e,t=process.env){return"1"===t[k("SKIP_AUTO_UPDATE")]||"1"===t[k("DISABLE_AUTO_UPDATE")]||(!(!["--json","--non-interactive","--dry-run","--help","-h","--version","-v"].some(t=>e.includes(t))&&!v(e))||e.includes("update")||e.includes("completion"))}function P(t,n,a,i,u){try{r(l(t),{recursive:!0,mode:448});const c=`${t}.tmp-${process.pid}`,p={package_name:n,checked_at:a,latest:i.latest,source:i.source,registry:i.registry,errors:i.errors,...void 0===u?{}:{install_attempted_at:u,install_attempted_version:i.latest||void 0}};s(c,JSON.stringify(p),{encoding:"utf-8",mode:384}),o(c,t),e(t,384)}catch(e){x.warn("Failed to persist update check cache:",e)}}const S=(e,t)=>c(e,t,{stdio:"inherit",timeout:45e3,killSignal:"SIGTERM"}),T=(e,t)=>c(process.execPath,[process.argv[1],...e],{stdio:"inherit",env:t});export async function runStartupUpdate(e,r={}){const o=r.env||process.env,s=r.localPackage||f(),a=r.globalInstall??isGlobalPackageInstall(s.root),l=r.npx??isNpxExecution(o);if(!a||l||shouldSkipStartupUpdate(e,o))return{status:"skipped",handled:!1,source:null};const i=r.now??Date.now(),u=r.cachePath||resolveUpdateCachePath(o),c=function(e,r,o){try{if(!t(e))return null;const s=JSON.parse(n(e,"utf-8"));if(s.package_name!==r.name||!Number.isFinite(s.checked_at))return null;const a=s.latest?216e5:6e5;return o-s.checked_at>=a?null:{result:{current:r.version,latest:s.latest,up_to_date:s.latest?m(r.version,s.latest)>=0:null,source:s.source,registry:s.registry,errors:Array.isArray(s.errors)?s.errors:[],error:s.latest?null:(s.errors||[]).map(e=>`${e.source}: ${e.error}`).join("; ")||"unknown"},installAttemptedAt:s.latest&&s.install_attempted_version===s.latest&&Number.isFinite(s.install_attempted_at)?s.install_attempted_at:null}}catch{return null}}(u,s,i);let g=c?.result,x=c?.installAttemptedAt||null;if(g||(g=await d({localPackage:s,fetchFn:r.fetchFn}),P(u,s.name,i,g),x=null),!g.latest)return{status:"unavailable",handled:!1,source:null};if(g.up_to_date)return{status:"current",handled:!1,source:g.source};if(null!==x&&i-x<36e5)return{status:"update_failed",handled:!1,source:g.source};const v=r.output||console.log,y=r.errorOutput||console.error,$=r.installRunner||S,b=isPnpmGlobalInstall(s.root),I=b?"win32"===process.platform?"pnpm.cmd":"pnpm":"win32"===process.platform?"npm.cmd":"npm",E=b?null:resolveNpmGlobalPrefix(s.root);v(A(p.cyan,h.t("update.auto_installing",{version:g.latest})));let N=null,U="unknown";for(const e of _.map(e=>e.registry)){const t=$(I,b?["add","--global",`${s.name}@${g.latest}`,"--registry",e]:["install","--global",...E?["--prefix",E]:[],`${s.name}@${g.latest}`,"--registry",e,"--no-audit","--no-fund","--fetch-timeout=15000","--fetch-retries=1","--fetch-retry-mintimeout=1000","--fetch-retry-maxtimeout=3000"]);if(0===t.status){N=e;break}U=t.error?.message||`exit ${t.status??"unknown"}`}if(!N)return P(u,s.name,i,g,i),y(A(p.yellow,h.t("update.auto_failed",{error:U}))),{status:"update_failed",handled:!1,source:g.source};v(A(p.green,h.t("update.auto_installed",{version:g.latest})));const w=(r.reexecRunner||T)(e,{...o,[k("SKIP_AUTO_UPDATE")]:"1"});return w.error?(y(A(p.yellow,h.t("update.reexec_failed",{error:w.error.message}))),{status:"update_failed",handled:!1,source:g.source}):(process.exitCode=w.status??1,{status:"reexecuted",handled:!0,source:g.source})}
@@ -1,13 +1,87 @@
1
+ export interface BrandGatewayAddress {
2
+ url: string;
3
+ label: string;
4
+ }
5
+ export interface BrandUpdateRegistry {
6
+ id: string;
7
+ label: string;
8
+ url: string;
9
+ }
10
+ export interface BrandPluginMarketplace {
11
+ name: string;
12
+ add: string;
13
+ probe: string;
14
+ }
15
+ export interface Brand {
16
+ id: string;
17
+ /** Provider name shown to users and written into tool configs, e.g. `name = "VibeAPI"` in Codex. */
18
+ displayName: string;
19
+ /** Name of the CLI product itself (banner, help, update messages). */
20
+ productName: string;
21
+ /** Brand short name (e.g. acme); the default command name. */
22
+ shortName?: string;
23
+ /** Primary command name (the package's first bin); defaults to shortName, then codekey. */
24
+ cliName: string;
25
+ /** Prefix of the env vars this CLI reads, e.g. `VIBECLI` → `VIBECLI_CONFIG_DIR`. */
26
+ envPrefix: string;
27
+ /** Directory under the home directory for config, logs and caches. */
28
+ configDirName: string;
29
+ /** Machine provider key used as the object/table key inside tool configs. */
30
+ providerKey: string;
31
+ /** Env-var key some tools read the API key from. */
32
+ apiKeyEnv: string;
33
+ /** Entry name in Claude Desktop's local config library. */
34
+ desktopEntryName: string;
35
+ /** npm package name used by the update check when package.json is unreadable. */
36
+ packageName: string;
37
+ /** Built-in gateway addresses; the order is the priority (first = main site). */
38
+ gatewayAddresses: BrandGatewayAddress[];
39
+ links: {
40
+ /** Console page where users create an API key. */
41
+ tokenPage: string;
42
+ /** Online command reference; omitted = help shows no docs link. */
43
+ commandDocs?: string;
44
+ };
45
+ /** China-reachable install mirrors; each one omitted = that tool installs from npmmirror / the official site. */
46
+ installMirror?: {
47
+ /** Base URL of `<tool>.sh` / `<tool>.ps1` one-line installers. */
48
+ scripts?: string;
49
+ /** Antigravity CLI download mirror carrying install.sh / install.ps1. */
50
+ agy?: string;
51
+ /** Claude Desktop download page for macOS / Windows. */
52
+ claudeDesktop?: string;
53
+ };
54
+ /** Claude Code plugin marketplaces tried before Anthropic's GitHub repo. */
55
+ pluginMarketplaces: BrandPluginMarketplace[];
56
+ /** Registries the self-update check queries, in order. */
57
+ updateRegistries: BrandUpdateRegistry[];
58
+ }
59
+ /** Command name of a brand that sets neither `cliName` nor `shortName`. */
60
+ export declare const NEUTRAL_CLI_NAME = "codekey";
1
61
  /**
2
- * Brand identity used when this CLI writes provider entries into third-party
3
- * tool config files (Codex, OpenClaw, Hermes, AtomCode, Grok Build, ...).
4
- *
5
- * Keeping these in one place makes a rebrand (or a white-label fork) a single-file
6
- * change instead of a grep-and-replace across every tool adapter.
62
+ * Fills the names a brand file may leave out: command = `cliName` → `shortName` (the brand's short
63
+ * name, e.g. acme) → `codekey`; env prefix and config directory follow from the command.
64
+ * Same rules as `resolveNames` in scripts/brands.mjs.
7
65
  */
66
+ export declare function normalizeBrand(raw: Record<string, unknown>): Record<string, unknown>;
67
+ /** Checks the runtime fields; throws with the first problem. */
68
+ export declare function validateBrand(raw: unknown, source?: string): Brand;
69
+ /** Reads one brand file (`brands/<id>.json` or a built `dist/brand.json`). */
70
+ export declare function loadBrandFile(path: string): Brand;
71
+ /** The brand this build was made for. */
72
+ export declare function brand(): Brand;
73
+ /** Swap the brand (tests only); returns a function that restores the previous one. */
74
+ export declare function setBrandForTests(next: Brand): () => void;
75
+ /** `process.env.<PREFIX>_<name>`, e.g. `brandEnv('TEST_HOME')` → `VIBECLI_TEST_HOME`. */
76
+ export declare function brandEnv(name: string): string | undefined;
77
+ export declare function brandEnvName(name: string): string;
78
+ /** Brand values the locale files reference as `{{brand}}`, `{{cli}}`, … */
79
+ export declare function brandTokens(locale: string): Record<string, string>;
8
80
  /** Human-facing provider name, e.g. shown as `name = "VibeAPI"` in Codex. */
9
- export declare const BRAND_NAME = "VibeAPI";
81
+ export declare const BRAND_NAME: string;
10
82
  /** Machine provider key used as the object/table key inside tool configs. */
11
- export declare const PROVIDER_KEY = "vibeapi";
83
+ export declare const PROVIDER_KEY: string;
12
84
  /** Env-var key some tools read the API key from. */
13
- export declare const API_KEY_ENV = "VIBEAPI_API_KEY";
85
+ export declare const API_KEY_ENV: string;
86
+ /** Primary command name, for "next step" hints such as `${CLI_NAME} setup --key <key>`. */
87
+ export declare const CLI_NAME: string;
package/dist/lib/brand.js CHANGED
@@ -1 +1 @@
1
- export const BRAND_NAME="VibeAPI";export const PROVIDER_KEY="vibeapi";export const API_KEY_ENV="VIBEAPI_API_KEY";
1
+ import{existsSync as e,readdirSync as r,readFileSync as t}from"fs";import{dirname as n,join as o}from"path";import{fileURLToPath as a}from"url";const i=["id","displayName","productName","cliName","envPrefix","configDirName","providerKey","apiKeyEnv","desktopEntryName","packageName"];export const NEUTRAL_CLI_NAME="codekey";export function normalizeBrand(e){const r=e.cliName??e.shortName??"codekey";return{...e,cliName:r,envPrefix:e.envPrefix??r.toUpperCase().replace(/-/g,"_"),configDirName:e.configDirName??`.${r}`}}export function validateBrand(e,r="brand"){if(!e||"object"!=typeof e)throw new Error(`${r}: not an object`);const t=normalizeBrand(e);for(const e of i)if("string"!=typeof t[e]||!t[e].trim())throw new Error(`${r}: ${e} is required`);if(!/^[a-z][a-z0-9-]*$/.test(t.cliName))throw new Error(`${r}: cliName must be a lowercase command name`);if(!/^[A-Z][A-Z0-9_]*$/.test(t.envPrefix))throw new Error(`${r}: envPrefix must be UPPER_SNAKE`);if(!/^[a-z][a-z0-9-]*$/.test(t.providerKey))throw new Error(`${r}: providerKey must be lowercase`);const n=t.gatewayAddresses;if(!Array.isArray(n)||0===n.length||n.some(e=>!e||"string"!=typeof e.url||!/^https:\/\//.test(e.url)||"string"!=typeof e.label))throw new Error(`${r}: gatewayAddresses must be a non-empty list of { url: https://…, label }`);const o=t.links;if(!o||"string"!=typeof o.tokenPage)throw new Error(`${r}: links.tokenPage is required`);if(!Array.isArray(t.pluginMarketplaces))throw new Error(`${r}: pluginMarketplaces must be a list`);if(!Array.isArray(t.updateRegistries)||0===t.updateRegistries.length)throw new Error(`${r}: updateRegistries must be a non-empty list`);return t}export function loadBrandFile(e){return validateBrand(JSON.parse(t(e,"utf-8")),e)}let s=function(){const i=n(a(import.meta.url)),s=o(i,"..","brand.json");if(e(s))return loadBrandFile(s);const d=o(i,"..","..","brands");for(const n of e(d)?r(d).filter(e=>e.endsWith(".json")).sort():[]){const e=JSON.parse(t(o(d,n),"utf-8"));if(!0===e.default)return validateBrand(e,o(d,n))}throw new Error(`brand.json not found next to ${i}`)}();export function brand(){return s}export function setBrandForTests(e){const r=s;return s=e,()=>{s=r}}export function brandEnv(e){return process.env[brandEnvName(e)]}export function brandEnvName(e){return`${s.envPrefix}_${e}`}function d(e,r){return"zh_CN"===r?e.join("、"):e.length>1?`${e.slice(0,-1).join(", ")} and ${e[e.length-1]}`:e.join("")}export function brandTokens(e){const r=new URL(s.gatewayAddresses[0].url),t=s.gatewayAddresses[1]?.url??s.gatewayAddresses[0].url;return{brand:s.displayName,product:s.productName,cli:s.cliName,configDir:s.configDirName,envPrefix:s.envPrefix,siteHost:r.host,altSiteUrl:t,updateSources:d(s.updateRegistries.map(e=>e.label),e)}}export const BRAND_NAME=s.displayName;export const PROVIDER_KEY=s.providerKey;export const API_KEY_ENV=s.apiKeyEnv;export const CLI_NAME=s.cliName;
@@ -5,7 +5,7 @@ import type { Argument, Command, HelpConfiguration, Option } from 'commander';
5
5
  * data on each command, so `--help` and the generated docs/commands.*.md read
6
6
  * the same thing (see command-docs.ts).
7
7
  */
8
- export declare const DOCS_URL = "https://docs.vibeapi.cn/zh/docs/coding-tools/commands";
8
+ export declare const DOCS_URL: string | undefined;
9
9
  export interface HelpExample {
10
10
  /** The command line, e.g. `vibecli base auto`. */
11
11
  command: string;
@@ -1 +1 @@
1
- import{i18n as e}from"./i18n.js";import{stringWidth as t}from"../utils/string-width.js";export const DOCS_URL="https://docs.vibeapi.cn/zh/docs/coding-tools/commands";const n=new WeakMap;export function attachCommandHelp(e,t){return n.set(e,{when:"",prerequisites:[],alternatives:[],sections:[],examples:[],...t}),e.addHelpText("after",()=>renderHelpExtras(e)),e}export function getCommandHelp(e){return n.get(e)??{when:"",prerequisites:[],alternatives:[],sections:[],examples:[]}}export function commandPath(e){const t=[];for(let n=e;n;n=n.parent)t.unshift(n.name());return t.join(" ")}function o(e){let t=e;for(;t.parent;)t=t.parent;return t}export function visibleSubcommands(e){return e.commands.filter(e=>!e._hidden)}const r=34;function i(e){const n=e.filter(([,e])=>e),o=Math.min(r,Math.max(0,...n.map(([e])=>t(e)))),i=[];for(const[n,r]of e){const e=t(n);r?e>o?i.push(` ${n}`,` ${" ".repeat(o)} ${r}`):i.push(` ${n}${" ".repeat(o-e)} ${r}`):i.push(` ${n}`)}return i}export function learnMoreRows(t){const n=[];if(visibleSubcommands(t).length>0){const o=t.parent?e.t("help.placeholder.subcommand"):e.t("help.placeholder.command");n.push([`${commandPath(t)} ${o} --help`,e.t("help.learn_more.command_help")])}return t.parent&&n.push([`${commandPath(o(t))} --help`,e.t("help.learn_more.all_commands")]),n.push(["vibecli help exit-codes",e.t("help.learn_more.exit_codes")]),n.push(["vibecli help environment",e.t("help.learn_more.environment")]),n.push([e.t("help.learn_more.docs",{url:DOCS_URL}),""]),n}export function renderHelpExtras(t){const n=getCommandHelp(t),o=[];for(const e of n.sections)o.push("",e.title,...i(e.rows));return n.when&&o.push("",e.t("help.title.when"),...n.when.split("\n").map(e=>` ${e}`)),n.prerequisites.length>0&&o.push("",e.t("help.title.prerequisites"),...n.prerequisites.map(e=>` - ${e}`)),n.alternatives.length>0&&o.push("",e.t("help.title.alternatives"),...i(n.alternatives.map(e=>[e.command,e.note]))),n.examples.length>0&&o.push("",e.t("help.title.examples"),...i(n.examples.map(e=>[e.command,e.note]))),o.push("",e.t("help.title.learn_more"),...i(learnMoreRows(t))),o.join("\n")}const s={"Usage:":"help.title.usage","Arguments:":"help.title.arguments","Options:":"help.title.options","Global Options:":"help.title.global_options","Commands:":"help.title.commands"};export function localizeTitle(t){const n=s[t];return n?e.t(n):t}function l(t,n,o){if(void 0===n)return t;const r=o??("string"==typeof n?n:JSON.stringify(n)),i=e.t("help.default_value",{value:r});return t?`${t}(${i})`:i}export function describeOption(e){return e.required||e.optional?l(e.description,e.defaultValue,e.defaultValueDescription):e.description}export function describeArgument(e){return l(e.description,e.defaultValue,e.defaultValueDescription)}export function helpConfiguration(){return{showGlobalOptions:!0,styleTitle:e=>localizeTitle(e),optionDescription:e=>describeOption(e),argumentDescription:e=>describeArgument(e)}}export function firstCommandWord(e){for(let t=0;t<e.length;t+=1){const n=e[t];if("--"===n)return;if("--base"!==n){if(!n.startsWith("-"))return n}else t+=1}}export function isHelpRequest(e){for(const t of e){if("--"===t)break;if("-h"===t||"--help"===t)return!0}return"help"===firstCommandWord(e)}export function renderHelpTopic(t){const n="exit-codes"===t?"exit_codes":"environment"===t?"environment":null;return n?`${e.t(`help_topics.${n}.title`)}\n\n${e.t(`help_topics.${n}.body`)}\n`:null}
1
+ import{i18n as e}from"./i18n.js";import{stringWidth as t}from"../utils/string-width.js";import{brand as n,CLI_NAME as r}from"./brand.js";export const DOCS_URL=n().links.commandDocs;const o=new WeakMap;export function attachCommandHelp(e,t){return o.set(e,{when:"",prerequisites:[],alternatives:[],sections:[],examples:[],...t}),e.addHelpText("after",()=>renderHelpExtras(e)),e}export function getCommandHelp(e){return o.get(e)??{when:"",prerequisites:[],alternatives:[],sections:[],examples:[]}}export function commandPath(e){const t=[];for(let n=e;n;n=n.parent)t.unshift(n.name());return t.join(" ")}function i(e){let t=e;for(;t.parent;)t=t.parent;return t}export function visibleSubcommands(e){return e.commands.filter(e=>!e._hidden)}const s=34;function l(e){const n=e.filter(([,e])=>e),r=Math.min(s,Math.max(0,...n.map(([e])=>t(e)))),o=[];for(const[n,i]of e){const e=t(n);i?e>r?o.push(` ${n}`,` ${" ".repeat(r)} ${i}`):o.push(` ${n}${" ".repeat(r-e)} ${i}`):o.push(` ${n}`)}return o}export function learnMoreRows(t){const n=[];if(visibleSubcommands(t).length>0){const r=t.parent?e.t("help.placeholder.subcommand"):e.t("help.placeholder.command");n.push([`${commandPath(t)} ${r} --help`,e.t("help.learn_more.command_help")])}return t.parent&&n.push([`${commandPath(i(t))} --help`,e.t("help.learn_more.all_commands")]),n.push([`${r} help exit-codes`,e.t("help.learn_more.exit_codes")]),n.push([`${r} help environment`,e.t("help.learn_more.environment")]),DOCS_URL&&n.push([e.t("help.learn_more.docs",{url:DOCS_URL}),""]),n}export function renderHelpExtras(t){const n=getCommandHelp(t),r=[];for(const e of n.sections)r.push("",e.title,...l(e.rows));return n.when&&r.push("",e.t("help.title.when"),...n.when.split("\n").map(e=>` ${e}`)),n.prerequisites.length>0&&r.push("",e.t("help.title.prerequisites"),...n.prerequisites.map(e=>` - ${e}`)),n.alternatives.length>0&&r.push("",e.t("help.title.alternatives"),...l(n.alternatives.map(e=>[e.command,e.note]))),n.examples.length>0&&r.push("",e.t("help.title.examples"),...l(n.examples.map(e=>[e.command,e.note]))),r.push("",e.t("help.title.learn_more"),...l(learnMoreRows(t))),r.join("\n")}const p={"Usage:":"help.title.usage","Arguments:":"help.title.arguments","Options:":"help.title.options","Global Options:":"help.title.global_options","Commands:":"help.title.commands"};export function localizeTitle(t){const n=p[t];return n?e.t(n):t}function a(t,n,r){if(void 0===n)return t;const o=r??("string"==typeof n?n:JSON.stringify(n)),i=e.t("help.default_value",{value:o});return t?`${t}(${i})`:i}export function describeOption(e){return e.required||e.optional?a(e.description,e.defaultValue,e.defaultValueDescription):e.description}export function describeArgument(e){return a(e.description,e.defaultValue,e.defaultValueDescription)}export function helpConfiguration(){return{showGlobalOptions:!0,styleTitle:e=>localizeTitle(e),optionDescription:e=>describeOption(e),argumentDescription:e=>describeArgument(e)}}export function firstCommandWord(e){for(let t=0;t<e.length;t+=1){const n=e[t];if("--"===n)return;if("--base"!==n){if(!n.startsWith("-"))return n}else t+=1}}export function isHelpRequest(e){for(const t of e){if("--"===t)break;if("-h"===t||"--help"===t)return!0}return"help"===firstCommandWord(e)}export function renderHelpTopic(t){const n="exit-codes"===t?"exit_codes":"environment"===t?"environment":null;return n?`${e.t(`help_topics.${n}.title`)}\n\n${e.t(`help_topics.${n}.body`)}\n`:null}
@@ -1 +1 @@
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)}}
1
+ import{CLIENT_CONFIG_PATH as e}from"./gateway-protocol.js";import{logger as t}from"../utils/logger.js";import{bundledClientConfig as o,parseClientConfig as n,readCachedClientConfig as r,setClientConfigSiteResolver as i,writeCachedClientConfig as c}from"./client-config.js";import{configManager as f}from"./config.js";import{getBuiltinGatewayAddresses as s,reloadRegistry as l}from"./model-registry.js";import{brandEnv as g,brand as a}from"./brand.js";export const CLIENT_CONFIG_TTL_MS=3e5;function u(e){try{return new URL(e).origin}catch{return e.replace(/\/+$/,"")}}export function clientConfigSite(e=f.getBaseUrl()){const t=u(e);return s().some(e=>u(e.url)===t)?a().id:t}i(()=>clientConfigSite());let d=null;export function lastClientConfigStatus(){return d}function m(e){const t=r();if(t&&t.site===clientConfigSite())return{config:t.config,source:"cache",revision:t.config.revision,fetchedAt:t.fetchedAt,problem:e};const n=o();return n?{config:n,source:"bundled",revision:n.revision,problem:e}:{config:null,source:null,problem:e}}export async function refreshClientConfig(i={}){const{force:s=!1,timeoutMs:u=8e3,fetchFn:h=fetch,now:p=Date.now()}=i;if("1"===g("DISABLE_CLIENT_CONFIG_FETCH"))return d=m(),d;const C=clientConfigSite(),v=r(),w=v&&v.site===C?v:null;if(!s&&w&&p-w.fetchedAt<3e5)return d={config:w.config,source:"cache",revision:w.config.revision,fetchedAt:w.fetchedAt},d;const A=w?.config??(C===a().id?o():null),T=new AbortController,b=setTimeout(()=>T.abort(),u);try{const o={};w?.etag&&(o["If-None-Match"]=w.etag);const r=await h(`${f.getBaseUrl()}${e}`,{method:"GET",headers:o,signal:T.signal});if(304===r.status&&w)return c({...w,fetchedAt:p}),d={config:w.config,source:"cloud",revision:w.config.revision,fetchedAt:p},d;if(!r.ok)return d=m(`HTTP ${r.status}`),d;const i=await r.json(),{config:s,problem:g}=n(i?.data,A);if(!s)return t.warn(`Gateway client config refused: ${g}`),d=m(`refused: ${g}`),d;g&&t.warn(`Gateway client config: ${g}`);const a=r.headers.get("etag")??void 0;return c({site:C,fetchedAt:p,config:s,...a?{etag:a}:{}}),l(),d={config:s,source:"cloud",revision:s.revision,fetchedAt:p,...g?{problem:g}:{}},d}catch(e){return t.logError("refreshClientConfig",e),d=m(e instanceof Error?e.message:String(e)),d}finally{clearTimeout(b)}}
@@ -22,12 +22,12 @@ export interface GatewayClientModel {
22
22
  /** Per-tool switches (`claude-code`, `codex`, `grok`): false keeps it out, true puts it in. */
23
23
  clients?: Record<string, boolean>;
24
24
  /** Only vibecli at or above this version sees the row. */
25
- minVibecliVersion?: string;
25
+ minClientVersion?: string;
26
26
  /** Staged rollout 0–100 by install id; absent = everyone. */
27
27
  rolloutPercent?: number;
28
28
  }
29
29
  /** vibecli 自己那一节(与 models.json 字段一一对应,snake_case)。 */
30
- export interface VibecliSection {
30
+ export interface ClientSection {
31
31
  minVersion?: string;
32
32
  defaultModels?: Record<string, string>;
33
33
  retiredDefaultModels?: Record<string, string[]>;
@@ -43,7 +43,8 @@ export interface ClientConfig {
43
43
  schema: number;
44
44
  revision: string;
45
45
  models: Record<string, GatewayClientModel[]>;
46
- vibecli?: VibecliSection;
46
+ /** The gateway's section for this CLI (`CLIENT_SECTION` on the wire). */
47
+ client?: ClientSection;
47
48
  }
48
49
  export type ClientConfigSource = 'cloud' | 'cache' | 'bundled';
49
50
  export interface CachedClientConfig {
@@ -96,5 +97,5 @@ export declare function isEligible(model: GatewayClientModel): boolean;
96
97
  /** Rows this install may not see turn into `hidden` (so the built-in entry of the same id stays out too). */
97
98
  export declare function eligibleLists(models: Record<string, GatewayClientModel[]>): Record<string, GatewayClientModel[]>;
98
99
  /** The vibecli section when this client is new enough for it. */
99
- export declare function usableVibecliSection(config: ClientConfig | null | undefined): VibecliSection | undefined;
100
+ export declare function usableClientSection(config: ClientConfig | null | undefined): ClientSection | undefined;
100
101
  export {};
@@ -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","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}
1
+ import{createHash as t,randomUUID as e}from"crypto";import{existsSync as n,mkdirSync as o,readFileSync as i,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";import{CLIENT_SECTION as u,MIN_CLIENT_VERSION as d}from"./gateway-protocol.js";import{brand as m,brandEnv as p}from"./brand.js";export const CLIENT_CONFIG_SCHEMA=1;const h=new Set(["haiku","sonnet","opus","reasoning","fable"]),g=/^[A-Za-z0-9._:@/\-[\]]{1,200}$/,_=/^[a-z][a-z0-9-]{0,31}$/,b=/^\d+(\.\d+){0,3}$/,y=t=>!!t&&"object"==typeof t&&!Array.isArray(t),C=t=>"number"==typeof t&&Number.isFinite(t)&&t>0?Math.floor(t):void 0;function $(t){if(!y(t)||"string"!=typeof t.id||!t.id.trim())return null;const e={id:t.id.trim()};if(!0===t.hidden)return{...e,hidden:!0};"string"==typeof t.name&&t.name.trim()&&(e.name=t.name.trim()),"string"==typeof t.description&&t.description.trim()&&(e.description=t.description.trim());const n=C(t.context_window);n&&(e.contextWindow=n);const o=C(t.auto_compact_tokens);if(o&&(e.autoCompactTokens=o),y(t.clients)){const n={};for(const[e,o]of Object.entries(t.clients))_.test(e)&&"boolean"==typeof o&&(n[e]=o);Object.keys(n).length>0&&(e.clients=n)}const i=t[d];return"string"==typeof i&&b.test(i)&&(e.minClientVersion=i),"number"==typeof t.rollout_percent&&t.rollout_percent>=0&&t.rollout_percent<=100&&(e.rolloutPercent=t.rollout_percent),e}function k(t,e,n,o){if(void 0===t)return{};if(!y(t))throw new Error(`${u}.${o} must be an object`);const i={};for(const[r,s]of Object.entries(t)){if(!e.test(r)||"string"!=typeof s||!n(s))throw new Error(`${u}.${o}.${r} is invalid`);i[r]=s}return i}function v(t,e,{nonEmpty:n=!1}={}){if(void 0===t)return[];if(!Array.isArray(t)||t.some(t=>"string"!=typeof t||!g.test(t)))throw new Error(`${u}.${e} must be a list of model ids`);if(n&&0===t.length)throw new Error(`${u}.${e} must not be empty`);return[...t]}function w(t,e,n){if(void 0===t)return{};if(!y(t))throw new Error(`${u}.${e} must be an object`);const o={};for(const[i,r]of Object.entries(t)){if(!h.has(i))throw new Error(`${u}.${e}.${i} is not a tier slot`);o[i]=v(r,`${e}.${i}`,{nonEmpty:n})}return o}const j=t=>(t??[]).filter(t=>!t.hidden).length;export function parseClientConfig(t,e){if(!y(t))return{config:null,problem:"not an object"};if(1!==t.schema)return{config:null,problem:`unsupported schema ${String(t.schema)}`};if(!y(t.models))return{config:null,problem:"models is not an object"};const n={};for(const[e,o]of Object.entries(t.models)){if(!Array.isArray(o))return{config:null,problem:`models.${e} is not a list`};const t=o.map($);if(t.some(t=>null===t))return{config:null,problem:`models.${e} has a row without an id`};n[e]=t}let o,i;try{o=function(t){if(null==t)return;if(!y(t))throw new Error(`${u} must be an object`);const e={};if(void 0!==t.min_version){if("string"!=typeof t.min_version||t.min_version&&!b.test(t.min_version))throw new Error(`${u}.min_version is invalid`);t.min_version&&(e.minVersion=t.min_version)}const n=k(t.default_models,/^(haiku|sonnet|opus|reasoning|fable)$/,t=>g.test(t),"default_models");Object.keys(n).length&&(e.defaultModels=n);const o=w(t.retired_default_models,"retired_default_models",!1);Object.keys(o).length&&(e.retiredDefaultModels=o);const i=k(t.tool_defaults,_,t=>""===t||g.test(t),"tool_defaults");Object.keys(i).length&&(e.toolDefaults=i);const r=w(t.tier_chains,"tier_chains",!0);Object.keys(r).length&&(e.tierChains=r);const s=v(t.retired_models,"retired_models");s.length&&(e.retiredModels=s);const l=k(t.tool_min_versions,_,t=>""===t||b.test(t),"tool_min_versions");Object.keys(l).length&&(e.toolMinVersions=l);const c=v(t.agy_models,"agy_models");c.length&&(e.agyModels=c);const f=v(t.one_million_fallback,"one_million_fallback");return f.length&&(e.oneMillionFallback=f),!0===t.accept_shrink&&(e.acceptShrink=!0),e}(t[u])}catch(t){i=`${u} section dropped: ${t instanceof Error?t.message:String(t)}`}const r=t[u];if(e&&(!y(r)||!0!==r.accept_shrink))for(const[t,o]of Object.entries(e.models)){const e=j(o),i=j(n[t]);if(e>0&&0===i||e>=4&&2*i<e)return{config:null,problem:`models.${t} shrank from ${e} to ${i}`}}return{config:{schema:1,revision:"string"==typeof t.revision?t.revision:"",models:n,...o?{client:o}:{}},problem:i}}export function serializeClientConfig(t){const e=Object.fromEntries(Object.entries(t.models).map(([t,e])=>[t,e.map(t=>({id:t.id,...t.hidden?{hidden:!0}:{},...t.name?{name:t.name}:{},...t.description?{description:t.description}:{},...t.contextWindow?{context_window:t.contextWindow}:{},...t.autoCompactTokens?{auto_compact_tokens:t.autoCompactTokens}:{},...t.clients?{clients:t.clients}:{},...t.minClientVersion?{[d]:t.minClientVersion}:{},...void 0!==t.rolloutPercent?{rollout_percent:t.rolloutPercent}:{}}))])),n=t.client,o=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:t.schema,revision:t.revision,models:e,...o?{[u]:o}:{}}}function O(){const t=p("CONFIG_DIR")?.trim();if(t)return t;const e=p("TEST_HOME")?.trim();return f(e||l(),m().configDirName)}export const cachePath=()=>f(O(),"client-config.json");function x(t,e){o(c(t),{recursive:!0});const n=`${t}.${process.pid}.tmp`;s(n,e,"utf-8"),r(n,t)}export function readCachedClientConfig(){try{if(!n(cachePath()))return null;const t=JSON.parse(i(cachePath(),"utf-8"));if("string"!=typeof t.site||"number"!=typeof t.fetchedAt)return null;const{config:e}=parseClientConfig(t.config);return e?{site:t.site,fetchedAt:t.fetchedAt,config:e,..."string"==typeof t.etag?{etag:t.etag}:{}}:null}catch{return null}}export function writeCachedClientConfig(t){x(cachePath(),JSON.stringify({site:t.site,etag:t.etag,fetchedAt:t.fetchedAt,config:serializeClientConfig(t.config)},null,2)+"\n")}let E;export function bundledClientConfig(){if("1"===p("NO_BUNDLED_CLIENT_CONFIG"))return null;if(void 0!==E)return E;E=null;const t=c(a(import.meta.url));for(const e of[f(t,"..","..","client-config.snapshot.json"),f(t,"..","client-config.snapshot.json")])try{if(!n(e))continue;E=parseClientConfig(JSON.parse(i(e,"utf-8"))).config;break}catch{}return E}let M=null;export function setClientConfigSiteResolver(t){M=t}export function currentClientConfig(){const t=readCachedClientConfig();let e=null;try{e=M?M():null}catch{e=null}if(t&&null!==e&&t.site===e)return{config:t.config,source:"cache",fetchedAt:t.fetchedAt};const n=bundledClientConfig();return n?{config:n,source:"bundled"}:null}let V=null,A=null;export function setClientIdentityForTests(t,e){V=t,A=e}export const clientVersion=()=>V??function(){try{const t=c(a(import.meta.url));for(const e of[f(t,"..","..","package.json"),f(t,"..","package.json")])if(n(e))return String(JSON.parse(i(e,"utf-8")).version??"0.0.0")}catch{}return"0.0.0"}();function S(t,e){const n=t.split(".").map(t=>parseInt(t,10)||0),o=e.split(".").map(t=>parseInt(t,10)||0);for(let t=0;t<Math.max(n.length,o.length);t++){const e=(n[t]??0)-(o[t]??0);if(e)return e}return 0}export function installId(){if(A)return A;const t=f(O(),"install-id");try{if(n(t)){const e=i(t,"utf-8").trim();if(e)return e}const o=e();return x(t,o+"\n"),o}catch{return"unknown"}}export function rolloutBucket(e){return t("sha256").update(`${installId()}:${e}`).digest().readUInt32BE(0)%100}export function isEligible(t){return!(t.minClientVersion&&S(clientVersion(),t.minClientVersion)<0||void 0!==t.rolloutPercent&&rolloutBucket(t.id)>=t.rolloutPercent)}export function eligibleLists(t){return Object.fromEntries(Object.entries(t).map(([t,e])=>[t,e.map(t=>t.hidden||isEligible(t)?t:{id:t.id,hidden:!0})]))}export function usableClientSection(t){const e=t?.client;if(e&&!(e.minVersion&&S(clientVersion(),e.minVersion)<0))return e}
@@ -1 +1 @@
1
- import{spawnSync as e}from"child_process";import{closeSync as o,copyFileSync as t,createReadStream as r,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as a,readFileSync as c,readSync as f,readdirSync as l,renameSync as d,statSync as m,utimesSync as p,writeFileSync as u}from"fs";import{join as h}from"path";import{pipeline as y}from"stream/promises";import*as g from"@iarna/toml";import{toolHome as v}from"./tools/types.js";export function codexHome(){return process.env.CODEX_HOME?.trim()||h(v(),".codex")}export function currentCodexProvider(){try{const e=g.parse(c(h(codexHome(),"config.toml"),"utf-8"));return"string"==typeof e.model_provider&&e.model_provider.trim()?e.model_provider.trim():"openai"}catch{return"openai"}}let b=()=>"win32"===process.platform?`${e("powershell.exe",["-NoProfile","-NonInteractive","-Command","(Get-Process -Name codex -ErrorAction SilentlyContinue).Id"],{encoding:"utf-8",windowsHide:!0}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number):`${e("pgrep",["-x","-i","codex"],{encoding:"utf-8"}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);export function setCodexProcessCheckForTests(e){b=e}export function runningCodexPids(){try{return b()}catch{return[]}}function x(e){const t=a(e,"r");try{const e=[],o=Buffer.alloc(65536);for(;;){const r=f(t,o,0,o.length,null);if(r<=0)break;const n=o.subarray(0,r).indexOf(10);if(n>=0){e.push(Buffer.from(o.subarray(0,n)));break}e.push(Buffer.from(o.subarray(0,r)))}return Buffer.concat(e).toString("utf-8")}finally{o(t)}}async function S(e,o,t){const{atime:s,mtime:i}=m(e),a=`${e}.vibecli-tmp`,c=n(a);c.write(o),await y(r(e,{start:t}),c),d(a,e),p(e,s,i)}async function w(e){try{return new((await import("node:sqlite")).DatabaseSync)(e)}catch(e){return`node:sqlite unavailable (Node ${process.versions.node}; needs 22.13+): ${e instanceof Error?e.message:String(e)}`}}export async function moveSessionsToProvider(e,o={}){const r=function(){const e=[],o=t=>{if(s(t))for(const r of l(t,{withFileTypes:!0})){const n=h(t,r.name);r.isDirectory()?o(n):r.isFile()&&r.name.endsWith(".jsonl")&&e.push(n)}};return o(h(codexHome(),"sessions")),o(h(codexHome(),"archived_sessions")),e}(),n=[];for(const o of r){let t,r;try{t=x(o)}catch{continue}try{r=JSON.parse(t)}catch{continue}const s=r.payload?.model_provider;"session_meta"===r.type&&"string"==typeof s&&s!==e&&(r.payload.model_provider=e,n.push({file:o,from:s,line:JSON.stringify(r),length:Buffer.byteLength(t,"utf-8")}))}const a=function(){const e=codexHome();if(!s(e))return null;const o=l(e).map(e=>/^state_(\d+)\.sqlite$/.exec(e)).filter(e=>!!e).sort((e,o)=>Number(o[1])-Number(e[1]));return o.length>0?h(e,o[0][0]):null}();let c=a?null:"no state DB",f=[],d=null;if(a){const o=await w(a);"string"==typeof o?c=o:(d=o,f=d.prepare('SELECT id, model_provider AS "from" FROM threads WHERE model_provider <> ?').all(e).map(e=>({id:String(e.id),from:String(e.from)})))}const m={target:e,scanned:r.length,moved:n.map(({file:e,from:o})=>({file:e,from:o})),dbRows:f.length,dbSkipped:c,backupDir:null};if(o.dryRun||0===n.length&&0===f.length)return d?.close(),m;const p=h(codexHome(),"backups",`vibecli-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);if(i(p,{recursive:!0}),a)for(const e of["","-wal","-shm"])s(a+e)&&t(a+e,h(p,`state.sqlite${e}`));const y={target:e,moved:m.moved,threads:f,db:a};u(h(p,"manifest.json"),JSON.stringify(y,null,2)+"\n");for(const e of n)await S(e.file,e.line,e.length);return d&&(d.prepare("UPDATE threads SET model_provider = ? WHERE model_provider <> ?").run(e,e),d.close()),m.backupDir=p,m}export async function undoSessionMove(e){const o=JSON.parse(c(h(e,"manifest.json"),"utf-8"));let t=0;for(const{file:e,from:r}of o.moved){if(!s(e))continue;const o=x(e),n=JSON.parse(o);n.payload&&(n.payload.model_provider=r,await S(e,JSON.stringify(n),Buffer.byteLength(o,"utf-8")),t+=1)}let r=0;if(o.db&&s(o.db)&&o.threads.length>0){const e=await w(o.db);if("string"!=typeof e){const t=e.prepare("UPDATE threads SET model_provider = ? WHERE id = ?");for(const{id:e,from:n}of o.threads)r+=Number(t.run(n,e).changes);e.close()}}return{files:t,dbRows:r}}
1
+ import{spawnSync as e}from"child_process";import{closeSync as o,copyFileSync as t,createReadStream as r,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as a,readFileSync as c,readSync as f,readdirSync as l,renameSync as d,statSync as m,utimesSync as p,writeFileSync as u}from"fs";import{join as h}from"path";import{pipeline as y}from"stream/promises";import*as g from"@iarna/toml";import{toolHome as b}from"./tools/types.js";import{CLI_NAME as v}from"./brand.js";export function codexHome(){return process.env.CODEX_HOME?.trim()||h(b(),".codex")}export function currentCodexProvider(){try{const e=g.parse(c(h(codexHome(),"config.toml"),"utf-8"));return"string"==typeof e.model_provider&&e.model_provider.trim()?e.model_provider.trim():"openai"}catch{return"openai"}}let x=()=>"win32"===process.platform?`${e("powershell.exe",["-NoProfile","-NonInteractive","-Command","(Get-Process -Name codex -ErrorAction SilentlyContinue).Id"],{encoding:"utf-8",windowsHide:!0}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number):`${e("pgrep",["-x","-i","codex"],{encoding:"utf-8"}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);export function setCodexProcessCheckForTests(e){x=e}export function runningCodexPids(){try{return x()}catch{return[]}}function S(e){const t=a(e,"r");try{const e=[],o=Buffer.alloc(65536);for(;;){const r=f(t,o,0,o.length,null);if(r<=0)break;const n=o.subarray(0,r).indexOf(10);if(n>=0){e.push(Buffer.from(o.subarray(0,n)));break}e.push(Buffer.from(o.subarray(0,r)))}return Buffer.concat(e).toString("utf-8")}finally{o(t)}}async function w(e,o,t){const{atime:s,mtime:i}=m(e),a=`${e}.${v}-tmp`,c=n(a);c.write(o),await y(r(e,{start:t}),c),d(a,e),p(e,s,i)}async function E(e){try{return new((await import("node:sqlite")).DatabaseSync)(e)}catch(e){return`node:sqlite unavailable (Node ${process.versions.node}; needs 22.13+): ${e instanceof Error?e.message:String(e)}`}}export async function moveSessionsToProvider(e,o={}){const r=function(){const e=[],o=t=>{if(s(t))for(const r of l(t,{withFileTypes:!0})){const n=h(t,r.name);r.isDirectory()?o(n):r.isFile()&&r.name.endsWith(".jsonl")&&e.push(n)}};return o(h(codexHome(),"sessions")),o(h(codexHome(),"archived_sessions")),e}(),n=[];for(const o of r){let t,r;try{t=S(o)}catch{continue}try{r=JSON.parse(t)}catch{continue}const s=r.payload?.model_provider;"session_meta"===r.type&&"string"==typeof s&&s!==e&&(r.payload.model_provider=e,n.push({file:o,from:s,line:JSON.stringify(r),length:Buffer.byteLength(t,"utf-8")}))}const a=function(){const e=codexHome();if(!s(e))return null;const o=l(e).map(e=>/^state_(\d+)\.sqlite$/.exec(e)).filter(e=>!!e).sort((e,o)=>Number(o[1])-Number(e[1]));return o.length>0?h(e,o[0][0]):null}();let c=a?null:"no state DB",f=[],d=null;if(a){const o=await E(a);"string"==typeof o?c=o:(d=o,f=d.prepare('SELECT id, model_provider AS "from" FROM threads WHERE model_provider <> ?').all(e).map(e=>({id:String(e.id),from:String(e.from)})))}const m={target:e,scanned:r.length,moved:n.map(({file:e,from:o})=>({file:e,from:o})),dbRows:f.length,dbSkipped:c,backupDir:null};if(o.dryRun||0===n.length&&0===f.length)return d?.close(),m;const p=h(codexHome(),"backups",`${v}-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);if(i(p,{recursive:!0}),a)for(const e of["","-wal","-shm"])s(a+e)&&t(a+e,h(p,`state.sqlite${e}`));const y={target:e,moved:m.moved,threads:f,db:a};u(h(p,"manifest.json"),JSON.stringify(y,null,2)+"\n");for(const e of n)await w(e.file,e.line,e.length);return d&&(d.prepare("UPDATE threads SET model_provider = ? WHERE model_provider <> ?").run(e,e),d.close()),m.backupDir=p,m}export async function undoSessionMove(e){const o=JSON.parse(c(h(e,"manifest.json"),"utf-8"));let t=0;for(const{file:e,from:r}of o.moved){if(!s(e))continue;const o=S(e),n=JSON.parse(o);n.payload&&(n.payload.model_provider=r,await w(e,JSON.stringify(n),Buffer.byteLength(o,"utf-8")),t+=1)}let r=0;if(o.db&&s(o.db)&&o.threads.length>0){const e=await E(o.db);if("string"!=typeof e){const t=e.prepare("UPDATE threads SET model_provider = ? WHERE id = ?");for(const{id:e,from:n}of o.threads)r+=Number(t.run(n,e).changes);e.close()}}return{files:t,dbRows:r}}
@@ -1 +1 @@
1
- import{i18n as t}from"./i18n.js";import{buildProgram as e}from"./program.js";import{commandPath as n,describeArgument as o,describeOption as s,getCommandHelp as p,visibleSubcommands as r,DOCS_URL as i}from"./cli-help.js";export const DOC_LOCALES=["zh_CN","en_US"];export function commandDocsPath(t){return`docs/commands.${t}.md`}function a(e,n){return t.t(`help.doc.${e}`,n)}function l(t){return t.replace(/[::]\s*$/,"")}function c(t){return"`"+t.replace(/\|/g,"\\|")+"`"}function m(t){return n(t).replace(/\s+/g,"-").toLowerCase()}function u(t){return`[${c(n(t))}](#${m(t)})`}function h(t,e){return[`| ${t[0]} | ${t[1]} |`,"| --- | --- |",...e.map(([t,e])=>{return`| ${t} | ${n=e,n.replace(/\|/g,"\\|").replace(/\n/g,"<br>")} |`;var n})]}function d(t){return t.createHelp().visibleOptions(t)}function f(t){return t.map(t=>[c(t.flags),s(t)])}function g(t){return t.split("\n").filter(Boolean).flatMap(t=>[t,""])}function $(t){return r(t).flatMap(t=>[t,...$(t)])}function x(e,s){const i=e.createHelp(),$=p(e),x=[`<a id="${m(e)}"></a>`,"",`## ${c(n(e))}`,""];x.push(...g(e.description())),x.push(`**${l(t.t("help.title.usage"))}**`,"","```text",i.commandUsage(e),"```","");const _=i.visibleArguments(e);_.length>0&&(x.push(`**${l(t.t("help.title.arguments"))}**`,""),x.push(...h([a("argument"),a("description")],_.map(t=>[c(i.argumentTerm(t)),o(t)])),"")),x.push(`**${l(t.t("help.title.options"))}**`,""),x.push(...h([a("option"),a("description")],f(d(e))),"");const b=s.options.map(t=>c(t.flags)).join(" ");x.push(a("global_inherited",{options:b,anchor:"global-options"}),"");const C=r(e);C.length>0&&(x.push(`**${l(t.t("help.title.commands"))}**`,""),x.push(...h([a("command"),a("description")],C.map(t=>[u(t),t.summary()||t.description()])),""));for(const t of $.sections)x.push(`**${l(t.title)}**`,""),x.push(...h([a("item"),a("description")],t.rows.map(([t,e])=>[c(t),e])),"");$.when&&x.push(`**${l(t.t("help.title.when"))}**`,"",...g($.when)),$.prerequisites.length>0&&x.push(`**${l(t.t("help.title.prerequisites"))}**`,"",...$.prerequisites.map(t=>`- ${t}`),""),$.alternatives.length>0&&(x.push(`**${l(t.t("help.title.alternatives"))}**`,""),x.push(...h([a("command"),a("use_instead")],$.alternatives.map(t=>[c(t.command),t.note])),"")),$.examples.length>0&&(x.push(`**${l(t.t("help.title.examples"))}**`,""),x.push(...h([a("command"),a("description")],$.examples.map(t=>[c(t.command),t.note])),""));const j=[c(`${n(e)} --help`)];return e.parent&&e.parent!==s&&j.push(u(e.parent)),j.push(`[${a("back_to_index")}](#commands)`),x.push(`**${a("see_also")}**: ${j.join(" · ")}`,""),x}function _(e){const n=[`\x3c!-- ${a("generated_note")} --\x3e`,"",`# ${a("title")}`,"",...g(e.description()),a("docs_link",{url:i}),"",'<a id="global-options"></a>',"",`## ${l(t.t("help.group.global_options"))}`,"",a("global_note"),"",...h([a("option"),a("description")],f(d(e))),"",'<a id="commands"></a>',"",`## ${l(t.t("help.title.commands"))}`,""],o=new Map;for(const n of r(e)){const e=n.helpGroup()||t.t("help.title.commands");o.set(e,[...o.get(e)??[],n])}for(const[t,e]of o)n.push(`### ${l(t)}`,""),n.push(...h([a("command"),a("description")],e.map(t=>[u(t),t.summary()||t.description()])),"");const s=p(e).examples;s.length>0&&(n.push(`## ${l(t.t("help.title.examples"))}`,""),n.push(...h([a("command"),a("description")],s.map(t=>[c(t.command),t.note])),""));for(const t of $(e))n.push(...x(t,e));return n.join("\n").replace(/\n{3,}/g,"\n\n").trimEnd()+"\n"}export function generateCommandDocs(n){const o=t.getLocale();t.loadFromConfig(n);try{return _(e())}finally{t.loadFromConfig(o)}}
1
+ import{i18n as t}from"./i18n.js";import{buildProgram as e}from"./program.js";import{commandPath as n,describeArgument as o,describeOption as s,getCommandHelp as p,visibleSubcommands as r,DOCS_URL as i}from"./cli-help.js";export const DOC_LOCALES=["zh_CN","en_US"];export function commandDocsPath(t){return`docs/commands.${t}.md`}function a(e,n){return t.t(`help.doc.${e}`,n)}function l(t){return t.replace(/[::]\s*$/,"")}function c(t){return"`"+t.replace(/\|/g,"\\|")+"`"}function m(t){return n(t).replace(/\s+/g,"-").toLowerCase()}function u(t){return`[${c(n(t))}](#${m(t)})`}function h(t,e){return[`| ${t[0]} | ${t[1]} |`,"| --- | --- |",...e.map(([t,e])=>{return`| ${t} | ${n=e,n.replace(/\|/g,"\\|").replace(/\n/g,"<br>")} |`;var n})]}function d(t){return t.createHelp().visibleOptions(t)}function f(t){return t.map(t=>[c(t.flags),s(t)])}function g(t){return t.split("\n").filter(Boolean).flatMap(t=>[t,""])}function $(t){return r(t).flatMap(t=>[t,...$(t)])}function x(e,s){const i=e.createHelp(),$=p(e),x=[`<a id="${m(e)}"></a>`,"",`## ${c(n(e))}`,""];x.push(...g(e.description())),x.push(`**${l(t.t("help.title.usage"))}**`,"","```text",i.commandUsage(e),"```","");const _=i.visibleArguments(e);_.length>0&&(x.push(`**${l(t.t("help.title.arguments"))}**`,""),x.push(...h([a("argument"),a("description")],_.map(t=>[c(i.argumentTerm(t)),o(t)])),"")),x.push(`**${l(t.t("help.title.options"))}**`,""),x.push(...h([a("option"),a("description")],f(d(e))),"");const b=s.options.map(t=>c(t.flags)).join(" ");x.push(a("global_inherited",{options:b,anchor:"global-options"}),"");const C=r(e);C.length>0&&(x.push(`**${l(t.t("help.title.commands"))}**`,""),x.push(...h([a("command"),a("description")],C.map(t=>[u(t),t.summary()||t.description()])),""));for(const t of $.sections)x.push(`**${l(t.title)}**`,""),x.push(...h([a("item"),a("description")],t.rows.map(([t,e])=>[c(t),e])),"");$.when&&x.push(`**${l(t.t("help.title.when"))}**`,"",...g($.when)),$.prerequisites.length>0&&x.push(`**${l(t.t("help.title.prerequisites"))}**`,"",...$.prerequisites.map(t=>`- ${t}`),""),$.alternatives.length>0&&(x.push(`**${l(t.t("help.title.alternatives"))}**`,""),x.push(...h([a("command"),a("use_instead")],$.alternatives.map(t=>[c(t.command),t.note])),"")),$.examples.length>0&&(x.push(`**${l(t.t("help.title.examples"))}**`,""),x.push(...h([a("command"),a("description")],$.examples.map(t=>[c(t.command),t.note])),""));const j=[c(`${n(e)} --help`)];return e.parent&&e.parent!==s&&j.push(u(e.parent)),j.push(`[${a("back_to_index")}](#commands)`),x.push(`**${a("see_also")}**: ${j.join(" · ")}`,""),x}function _(e){const n=[`\x3c!-- ${a("generated_note")} --\x3e`,"",`# ${a("title")}`,"",...g(e.description()),...i?[a("docs_link",{url:i})]:[],"",'<a id="global-options"></a>',"",`## ${l(t.t("help.group.global_options"))}`,"",a("global_note"),"",...h([a("option"),a("description")],f(d(e))),"",'<a id="commands"></a>',"",`## ${l(t.t("help.title.commands"))}`,""],o=new Map;for(const n of r(e)){const e=n.helpGroup()||t.t("help.title.commands");o.set(e,[...o.get(e)??[],n])}for(const[t,e]of o)n.push(`### ${l(t)}`,""),n.push(...h([a("command"),a("description")],e.map(t=>[u(t),t.summary()||t.description()])),"");const s=p(e).examples;s.length>0&&(n.push(`## ${l(t.t("help.title.examples"))}`,""),n.push(...h([a("command"),a("description")],s.map(t=>[c(t.command),t.note])),""));for(const t of $(e))n.push(...x(t,e));return n.join("\n").replace(/\n{3,}/g,"\n\n").trimEnd()+"\n"}export function generateCommandDocs(n){const o=t.getLocale();t.loadFromConfig(n);try{return _(e())}finally{t.loadFromConfig(o)}}
@@ -1 +1 @@
1
- import{i18n as n,detectSystemLang as r}from"./i18n.js";import{configManager as o}from"./config.js";import{runModelRefresh as e}from"./model-refresh.js";import{refreshClientConfig as t}from"./client-config-sync.js";import{normalizeBaseUrl as s}from"./gateway-addresses.js";import i from"chalk";import{setRuntimeOptions as m,detectColorPreferenceFromEnv as a,isColorEnabled as c,isJsonMode as g}from"./runtime-options.js";import{cleanupAnthropicEnvVars as l,machineEnvVarsLeft as u}from"./env-cleanup.js";import{runStartupUpdate as f}from"./auto-update.js";import{buildProgram as d}from"./program.js";import{firstCommandWord as p,isHelpRequest as h,renderHelpTopic as v}from"./cli-help.js";import{reportCliError as w,usageError as j,VibeCliError as _}from"./errors.js";export{buildProgram}from"./program.js";const y=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const e=o.isLangChosen()?o.getLang():r();n.loadFromConfig(e),this.program=d()}cleanupLeakedEnvVars(){const r=l();if(0===r.length||g())return;const o=n.t("messages.env_vars_cleared",{vars:r.join(", ")});console.log(c()?i.yellow(o):o);const e=u();if(e.length>0){const r=n.t("messages.env_vars_machine_left",{vars:e.join(", ")});console.log(c()?i.yellow(r):r)}}preflightArgs(n){const r=r=>n.includes(r),e=!r("--no-color")&&a();if(m({nonInteractive:r("--non-interactive"),json:r("--json"),yes:r("--yes")||r("-y"),dryRun:r("--dry-run"),color:e}),e||(i.level=0),this.configuring=!1,h(n))return;let t;for(let r=0;r<n.length;r+=1){const o=n[r];"--base"===o&&n[r+1]?(t=n[r+1],r+=1):o.startsWith("--base=")&&(t=o.slice(7))}const c=p(n),g=void 0===c&&!["--version","-v"].some(r);this.configuring=g||void 0!==c&&y.has(c),t&&o.setBaseUrl(s(t)??t,this.configuring)}async execute(n){try{if(this.preflightArgs(n),"help"===n[0]&&n[1]){const r=v(n[1]);if(r)return void process.stdout.write(r)}if(this.rejectUnknownCommand(n),!h(n)){if(this.configuring&&this.cleanupLeakedEnvVars(),(await f(n)).handled)return;this.configuring&&await t({timeoutMs:5e3}),await e(n)}await this.program.parseAsync(n,{from:"user"})}catch(r){if("commander.helpDisplayed"===r?.code||"commander.version"===r?.code)return;w(this.normalizeCommanderError(r,n))}}rejectUnknownCommand(r){const o=p(r);if(!o||"help"===o)return;if(this.program.commands.some(n=>n.name()===o))return;const e=this.suggestCommand(o),t=e?n.t("cli.unknown_hint_suggestion",{command:e}):n.t("cli.unknown_hint");throw j(n.t("cli.error_unknown",{command:o}),t,"unknown_command")}suggestCommand(n){const r=(n,r)=>{const o=Array.from({length:r.length+1},(n,r)=>r);for(let e=1;e<=n.length;e+=1){let t=o[0];o[0]=e;for(let s=1;s<=r.length;s+=1){const i=o[s];o[s]=Math.min(o[s]+1,o[s-1]+1,t+(n[e-1]===r[s-1]?0:1)),t=i}}return o[r.length]};return this.program.commands.map(n=>n.name()).map(o=>({name:o,score:r(n,o)})).filter(({score:r})=>r<=Math.max(2,Math.floor(n.length/2))).sort((n,r)=>n.score-r.score)[0]?.name}normalizeCommanderError(r,o){if(r instanceof _)return r;const e=r?.code,t=r instanceof Error?r.message:String(r);if("commander.unknownOption"===e||"commander.missingArgument"===e||"commander.missingMandatoryOption"===e||"commander.invalidArgument"===e){const r=p(o)??"vibecli",s=/'([^']+)'/.exec(t)?.[1]??"",i="commander.unknownOption"===e?"cli.err_unknown_option":"commander.missingArgument"===e?"cli.err_missing_argument":"commander.missingMandatoryOption"===e?"cli.err_missing_option":null,m=i&&s?n.t(i,{name:s}):t.replace(/^error:\s*/,"");return j(m,n.t("cli.unknown_option_hint",{command:r}),e)}return r}getProgram(){return this.program}}
1
+ import{i18n as n,detectSystemLang as r}from"./i18n.js";import{configManager as o}from"./config.js";import{runModelRefresh as e}from"./model-refresh.js";import{refreshClientConfig as t}from"./client-config-sync.js";import{normalizeBaseUrl as s}from"./gateway-addresses.js";import i from"chalk";import{setRuntimeOptions as m,detectColorPreferenceFromEnv as a,isColorEnabled as c,isJsonMode as g}from"./runtime-options.js";import{cleanupAnthropicEnvVars as l,machineEnvVarsLeft as u}from"./env-cleanup.js";import{runStartupUpdate as f}from"./auto-update.js";import{buildProgram as d}from"./program.js";import{firstCommandWord as p,isHelpRequest as h,renderHelpTopic as w}from"./cli-help.js";import{reportCliError as j,usageError as v,CliError as _}from"./errors.js";import{CLI_NAME as y}from"./brand.js";export{buildProgram}from"./program.js";const k=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const e=o.isLangChosen()?o.getLang():r();n.loadFromConfig(e),this.program=d()}cleanupLeakedEnvVars(){const r=l();if(0===r.length||g())return;const o=n.t("messages.env_vars_cleared",{vars:r.join(", ")});console.log(c()?i.yellow(o):o);const e=u();if(e.length>0){const r=n.t("messages.env_vars_machine_left",{vars:e.join(", ")});console.log(c()?i.yellow(r):r)}}preflightArgs(n){const r=r=>n.includes(r),e=!r("--no-color")&&a();if(m({nonInteractive:r("--non-interactive"),json:r("--json"),yes:r("--yes")||r("-y"),dryRun:r("--dry-run"),color:e}),e||(i.level=0),this.configuring=!1,h(n))return;let t;for(let r=0;r<n.length;r+=1){const o=n[r];"--base"===o&&n[r+1]?(t=n[r+1],r+=1):o.startsWith("--base=")&&(t=o.slice(7))}const c=p(n),g=void 0===c&&!["--version","-v"].some(r);this.configuring=g||void 0!==c&&k.has(c),t&&o.setBaseUrl(s(t)??t,this.configuring)}async execute(n){try{if(this.preflightArgs(n),"help"===n[0]&&n[1]){const r=w(n[1]);if(r)return void process.stdout.write(r)}if(this.rejectUnknownCommand(n),!h(n)){if(this.configuring&&this.cleanupLeakedEnvVars(),(await f(n)).handled)return;this.configuring&&await t({timeoutMs:5e3}),await e(n)}await this.program.parseAsync(n,{from:"user"})}catch(r){if("commander.helpDisplayed"===r?.code||"commander.version"===r?.code)return;j(this.normalizeCommanderError(r,n))}}rejectUnknownCommand(r){const o=p(r);if(!o||"help"===o)return;if(this.program.commands.some(n=>n.name()===o))return;const e=this.suggestCommand(o),t=e?n.t("cli.unknown_hint_suggestion",{command:e}):n.t("cli.unknown_hint");throw v(n.t("cli.error_unknown",{command:o}),t,"unknown_command")}suggestCommand(n){const r=(n,r)=>{const o=Array.from({length:r.length+1},(n,r)=>r);for(let e=1;e<=n.length;e+=1){let t=o[0];o[0]=e;for(let s=1;s<=r.length;s+=1){const i=o[s];o[s]=Math.min(o[s]+1,o[s-1]+1,t+(n[e-1]===r[s-1]?0:1)),t=i}}return o[r.length]};return this.program.commands.map(n=>n.name()).map(o=>({name:o,score:r(n,o)})).filter(({score:r})=>r<=Math.max(2,Math.floor(n.length/2))).sort((n,r)=>n.score-r.score)[0]?.name}normalizeCommanderError(r,o){if(r instanceof _)return r;const e=r?.code,t=r instanceof Error?r.message:String(r);if("commander.unknownOption"===e||"commander.missingArgument"===e||"commander.missingMandatoryOption"===e||"commander.invalidArgument"===e){const r=p(o)??y,s=/'([^']+)'/.exec(t)?.[1]??"",i="commander.unknownOption"===e?"cli.err_unknown_option":"commander.missingArgument"===e?"cli.err_missing_argument":"commander.missingMandatoryOption"===e?"cli.err_missing_option":null,m=i&&s?n.t(i,{name:s}):t.replace(/^error:\s*/,"");return v(m,n.t("cli.unknown_option_hint",{command:r}),e)}return r}getProgram(){return this.program}}
@@ -1,4 +1,4 @@
1
- export declare const DEFAULT_BASE_URL = "https://www.vibeapi.cn";
1
+ export declare const DEFAULT_BASE_URL: string;
2
2
  export declare const DEFAULT_MODELS: import("./model-registry.js").Models;
3
3
  export declare const DEFAULT_PROFILE_NAME = "default";
4
4
  export interface VibecliModels {
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as t,readFileSync as i,writeFileSync as o,renameSync as s,unlinkSync as r,readdirSync as n,rmdirSync as a,statSync as c,chmodSync as l}from"fs";import{join as f,dirname as g}from"path";import{homedir as h}from"os";import{createHash as p}from"crypto";import*as m from"js-yaml";import{logger as u}from"../utils/logger.js";import{getDefaultModels as y,isRetiredDefaultModel as d}from"./model-registry.js";import{readLegacySecretsFile as _}from"./secret-store.js";export const DEFAULT_BASE_URL="https://www.vibeapi.cn";export const DEFAULT_MODELS=y();export const DEFAULT_PROFILE_NAME="default";const k="plaintext";export class ConfigManager{static instance;configDir;configPath;config;runtimeBaseUrl;constructor(){this.configDir=this.resolveConfigDir(),this.migrateLegacyConfigDir(),this.configPath=f(this.configDir,"config.yaml"),this.config=this.loadConfig()}migrateLegacyConfigDir(){try{const t=f(g(this.configDir),".chelper");if(t===this.configDir||!e(t))return;if(["config.yaml","secrets.enc"].some(t=>e(f(this.configDir,t))))return;if(e(this.configDir)){for(const i of n(t)){const o=f(this.configDir,i);e(o)||s(f(t,i),o)}0===n(t).length&&a(t)}else s(t,this.configDir);u.record(`Migrated config dir: ${t} -> ${this.configDir}`)}catch(e){u.warn("Failed to migrate legacy .chelper config dir:",e)}}resolveConfigDir(){const e=process.env.VIBECLI_CONFIG_DIR;if(e&&e.trim())return e.trim();const t=process.env.VIBECLI_TEST_HOME;return t&&t.trim()?f(t.trim(),".vibecli"):f(h(),".vibecli")}createDefaultConfig(){return this.syncLegacyFields({lang:"en_US",active_profile:"default",profiles:{[DEFAULT_PROFILE_NAME]:{}},presets:{}})}normalizeModels(e){const t=t=>{const i=e?.[t]?.trim();return i&&!d(t,i)?i:DEFAULT_MODELS[t]},i={haiku:t("haiku"),sonnet:t("sonnet"),opus:t("opus"),reasoning:t("reasoning")};if(e&&"object"==typeof e)for(const[t,o]of Object.entries(e))t in i||"string"==typeof o&&o.trim()&&(i[t]=o.trim());return i}normalizeToolModels(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i={};for(const[e,o]of Object.entries(t))"string"==typeof o&&o.trim()&&(i[e]=o.trim());return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeToolSettings(e){if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||!t||"object"!=typeof t||Array.isArray(t))return[];const i=Object.fromEntries(Object.entries(t).filter(([,e])=>"string"==typeof e||"boolean"==typeof e||"number"==typeof e&&Number.isFinite(e)));return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeStringRecord(e){return!e||"object"!=typeof e||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(e=>"string"==typeof e[1]&&Boolean(e[1].trim())).map(([e,t])=>[e,t.trim()]))}normalizeProfile(e){if(!e)return{};const t=this.normalizeToolModels(e.tool_models),i=this.normalizeToolSettings(e.tool_settings),o=this.normalizeStringRecord(e.tool_api_keys);return{..."string"==typeof e.api_key&&e.api_key?{api_key:e.api_key}:{},...Object.keys(o).length>0?{tool_api_keys:o}:{},..."string"==typeof e.base_url&&e.base_url?{base_url:e.base_url}:{},...e.models?{models:this.normalizeModels(e.models)}:{},...Object.keys(t).length>0?{tool_models:t}:{},...Object.keys(i).length>0?{tool_settings:i}:{}}}normalizeProfiles(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>e&&"string"==typeof e&&t&&"object"==typeof t?[[e,this.normalizeProfile(t)]]:[]);return Object.fromEntries(t)}normalizePresets(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i=t;return i.models?[[e,{models:this.normalizeModels(i.models),updated_at:i.updated_at||new Date(0).toISOString()}]]:[]});return Object.fromEntries(t)}getResolvedActiveProfile(e){const t=e.active_profile||"default";return e.profiles?.[t]||{}}syncLegacyFields(e){const t=this.normalizeProfiles(e.profiles),i=e.active_profile?.trim()||Object.keys(t)[0]||"default",o=t[i]?t:{...t,[i]:{}},s=this.getResolvedActiveProfile({...e,profiles:o,active_profile:i});return{...e,lang:e.lang||"en_US",active_profile:i,profiles:o,presets:this.normalizePresets(e.presets),api_key:s.api_key,base_url:s.base_url,models:s.models?this.normalizeModels(s.models):DEFAULT_MODELS}}sanitizeBackupLabel(e){return(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}getBackupDir(){return f(this.configDir,"backups")}getLegacySecretsPath(){return f(this.configDir,"secrets.enc")}getSecretsBackupPath(e){return e.replace(/\.yaml$/,".secrets.enc")}static getInstance(){return ConfigManager.instance||(ConfigManager.instance=new ConfigManager),ConfigManager.instance}ensureConfigDir(){e(this.configDir)||t(this.configDir,{recursive:!0})}loadConfig(){try{if(e(this.configPath)){const t=i(this.configPath,"utf-8"),o=m.load(t);let s=this.migrateOldConfig(o||{lang:"en_US"}),n=!1;const a=this.getLegacySecretsPath();if(e(a)&&o?.credential_store!==k)try{s=this.mergeLegacySecrets(s,_(a)),n=!0}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecrets",e)}if((this.needsMigration(o)||n)&&(this.backupConfig(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(s))),n))try{r(a)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}try{l(this.configPath,384)}catch{}return s}const t=this.getLegacySecretsPath();if(e(t))try{const e=this.mergeLegacySecrets(this.createDefaultConfig(),_(t));this.ensureConfigDir(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(e)));try{r(t)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}return e}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecretsWithoutConfig",e)}}catch(e){u.warn("Failed to load config, using defaults:",e),u.logError("ConfigManager.loadConfig",e)}return this.createDefaultConfig()}needsMigration(e){return!(!e||"object"!=typeof e)&&("plan"in e||!("profiles"in e)||!("active_profile"in e)||!("presets"in e))}migrateOldConfig(e){if(!e||"object"!=typeof e)return this.createDefaultConfig();const t=e,{plan:i,...o}=t,s=this.normalizeProfiles(o.profiles),r=this.normalizeProfile({api_key:"string"==typeof o.api_key?o.api_key:void 0,base_url:"string"==typeof o.base_url?o.base_url:void 0,models:o.models}),n=Object.keys(s).length>0?s:{[DEFAULT_PROFILE_NAME]:r},a="string"==typeof o.active_profile&&o.active_profile.trim()?o.active_profile.trim():Object.keys(n)[0]||"default";return this.syncLegacyFields({lang:"string"==typeof o.lang&&o.lang?o.lang:"en_US",...!0===o.lang_chosen?{lang_chosen:!0}:{},...o.credential_store===k?{credential_store:k}:{},active_profile:a,profiles:n,presets:this.normalizePresets(o.presets)})}atomicWrite(t,i){const n=`${t}.tmp`;try{o(n,i,{encoding:"utf-8",mode:384}),s(n,t);try{l(t,384)}catch{}}catch(t){if(e(n))try{r(n)}catch{}throw t}}backupConfig(){if(!e(this.configPath))return;const s=this.getBackupDir();e(s)||t(s,{recursive:!0});const r=(new Date).toISOString().replace(/[:.]/g,"-"),n=f(s,`config-${r}.yaml`);try{const e=i(this.configPath,"utf-8");o(n,e,{encoding:"utf-8",mode:384}),this.rotateBackups(s,10,30)}catch(e){u.logError("ConfigManager.backupConfig",e)}}rotateBackups(t,i,o){try{const s=Date.now()-24*o*60*60*1e3,a=n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>({name:e,path:f(t,e),mtime:c(f(t,e)).mtime})).sort((e,t)=>t.mtime.getTime()-e.mtime.getTime()),l=new Set;a.slice(i).forEach(e=>l.add(e.path)),a.forEach(e=>{e.mtime.getTime()<s&&l.add(e.path)});for(const t of l){let i=!1;try{r(t),i=!0}catch(e){u.logError("ConfigManager.rotateBackups",e)}if(i){const i=this.getSecretsBackupPath(t);if(e(i))try{r(i)}catch(e){u.logError("ConfigManager.rotateBackups.secrets",e)}}}}catch(e){u.logError("ConfigManager.rotateBackups",e)}}saveConfig(e){try{this.ensureConfigDir(),this.backupConfig();const t=this.syncLegacyFields(this.migrateOldConfig(e||this.config)),i=this.prepareForPersistence(t),o=m.dump(i);this.atomicWrite(this.configPath,o),this.config=t}catch(e){throw u.error("Failed to save config:",e),u.logError("ConfigManager.saveConfig",e),e}}prepareForPersistence(e){const t={...e,credential_store:k};return delete t.api_key,delete t.base_url,delete t.models,t}mergeLegacySecrets(e,t){const i={...e.profiles||{}},o=new Set([...Object.keys(t.api_keys||{}),...Object.keys(t.tool_api_keys||{})]);for(const e of o){const o=i[e]||{},s=o.api_key||t.api_keys?.[e],r={...t.tool_api_keys?.[e]||{},...o.tool_api_keys||{}};i[e]={...o,...s?{api_key:s}:{},...Object.keys(r).length>0?{tool_api_keys:r}:{}}}return this.syncLegacyFields({...e,profiles:i})}getConfig(){return this.syncLegacyFields({...this.config})}updateConfig(e){this.saveConfig({...this.config,...e})}isFirstRun(){return!e(this.configPath)}getLang(){return this.config.lang||"en_US"}isLangChosen(){return!0===this.config.lang_chosen}setLang(e){this.updateConfig({lang:e,lang_chosen:!0})}getActiveProfileName(){return this.config.active_profile||"default"}listProfiles(){return Object.keys(this.config.profiles||{}).sort()}getProfile(e=this.getActiveProfileName()){const t=this.config.profiles?.[e]||{};return{...t.api_key?{api_key:t.api_key}:{},...t.tool_api_keys&&Object.keys(t.tool_api_keys).length>0?{tool_api_keys:this.normalizeStringRecord(t.tool_api_keys)}:{},...t.base_url?{base_url:t.base_url}:{},models:t.models?this.normalizeModels(t.models):DEFAULT_MODELS,...t.tool_models&&Object.keys(t.tool_models).length>0?{tool_models:this.normalizeToolModels(t.tool_models)}:{},...t.tool_settings&&Object.keys(t.tool_settings).length>0?{tool_settings:this.normalizeToolSettings(t.tool_settings)}:{}}}createProfile(e,t=this.getActiveProfileName()){const i=this.getProfile(t),o={...this.config.profiles||{},[e]:{...i.api_key?{api_key:i.api_key}:{},...i.base_url?{base_url:i.base_url}:{},models:this.normalizeModels(i.models)}};this.saveConfig({...this.config,profiles:o})}setActiveProfile(e){if(!this.config.profiles?.[e])throw new Error(`Profile not found: ${e}`);this.saveConfig({...this.config,active_profile:e})}updateProfile(e,t){const i=this.config.profiles?.[e]||{},o=t.models?this.normalizeModels({...i.models,...t.models}):i.models?this.normalizeModels(i.models):void 0,s={...i,...void 0!==t.api_key?{api_key:t.api_key}:{},...void 0!==t.base_url?{base_url:t.base_url}:{},...o?{models:o}:{}},r={...this.config.profiles||{},[e]:s};this.saveConfig({...this.config,profiles:r})}deleteProfile(e){const t={...this.config.profiles||{}};if(!t[e])return;const i=Object.keys(t).filter(t=>t!==e);if(0===i.length)throw new Error("At least one profile must remain");delete t[e];const o=this.getActiveProfileName()===e?i[0]:this.getActiveProfileName();this.saveConfig({...this.config,profiles:t,active_profile:o})}getApiKey(){return this.config.profiles?.[this.getActiveProfileName()]?.api_key}setApiKey(e){this.updateProfile(this.getActiveProfileName(),{api_key:e})}revokeApiKey(){const e=this.config.profiles?.[this.getActiveProfileName()]||{},{api_key:t,tool_api_keys:i,...o}=e,s={...this.config.profiles||{},[this.getActiveProfileName()]:o};this.saveConfig({...this.config,profiles:s})}getApiKeyFingerprint(){const e=this.getApiKey();return e?p("sha256").update(e).digest("hex").slice(0,12):""}getApiKeyForTool(e){const t=this.config.profiles?.[this.getActiveProfileName()];return t?.tool_api_keys?.[e]||t?.api_key||void 0}setToolApiKey(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...this.config.profiles||{},[i]:{...o,tool_api_keys:{...o.tool_api_keys||{},[e]:t}}};this.saveConfig({...this.config,profiles:s})}clearToolApiKey(e){const t=this.getActiveProfileName(),i=this.config.profiles?.[t]||{},{[e]:o,...s}=i.tool_api_keys||{},r={...i};Object.keys(s).length>0?r.tool_api_keys=s:delete r.tool_api_keys,this.saveConfig({...this.config,profiles:{...this.config.profiles||{},[t]:r}})}listToolApiKeys(){return Object.keys(this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys||{}).sort()}getToolApiKeyFingerprint(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys?.[e];return t?p("sha256").update(t).digest("hex").slice(0,12):""}getModels(){const e=this.config.profiles?.[this.getActiveProfileName()]?.models;return e?this.normalizeModels(e):DEFAULT_MODELS}setModels(e){this.updateProfile(this.getActiveProfileName(),{models:this.normalizeModels(e)})}updateModels(e){this.setModels(this.normalizeModels({...this.getModels(),...e}))}getModelsForTool(e){const t=this.getModels(),i=this.config.profiles?.[this.getActiveProfileName()]?.tool_models?.[e];return i?this.normalizeModels({...t,...i}):t}setToolModel(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...o.tool_models||{}};t&&0!==Object.keys(t).length?s[e]=t:delete s[e];const r={...o};Object.keys(s).length>0?r.tool_models=s:delete r.tool_models;const n={...this.config.profiles||{},[i]:r};this.saveConfig({...this.config,profiles:n})}getToolSettings(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e];return t?{...t}:{}}getToolSetting(e,t){return this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e]?.[t]}setToolSetting(e,t,i){if(this.getToolSetting(e,t)===i)return;const o=this.getActiveProfileName(),s=this.config.profiles?.[o]||{},r={...s.tool_settings||{}};r[e]={...r[e]||{},[t]:i};const n={...this.config.profiles||{},[o]:{...s,tool_settings:r}};this.saveConfig({...this.config,profiles:n})}getCustomPresets(){return{...this.config.presets||{}}}saveCustomPreset(e,t){const i={...this.config.presets||{},[e]:{models:this.normalizeModels(t),updated_at:(new Date).toISOString()}};this.saveConfig({...this.config,presets:i})}deleteCustomPreset(e){const t={...this.config.presets||{}};t[e]&&(delete t[e],this.saveConfig({...this.config,presets:t}))}listBackups(){const t=this.getBackupDir();return e(t)?n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>{const i=f(t,e);return{name:e,path:i,mtimeMs:c(i).mtimeMs}}).sort((e,t)=>t.mtimeMs-e.mtimeMs):[]}createBackup(s){this.ensureConfigDir();const r=this.getBackupDir();e(r)||t(r,{recursive:!0});const n=(new Date).toISOString().replace(/[:.]/g,"-"),a=this.sanitizeBackupLabel(s),c=f(r,a?`config-${n}-${a}.yaml`:`config-${n}.yaml`),l=e(this.configPath)?i(this.configPath,"utf-8"):m.dump(this.prepareForPersistence(this.getConfig()));return o(c,l,{encoding:"utf-8",mode:384}),this.rotateBackups(r,10,30),c}restoreBackup(t){if(!t||"."===t||".."===t||/[/\\]|\.\./.test(t))throw new Error(`Invalid backup name: ${t}`);const o=this.getBackupDir(),s=f(o,t);if(!e(s))throw new Error(`Backup not found: ${t}`);const r=i(s,"utf-8"),n=m.load(r),a=this.getSecretsBackupPath(s);let c=this.migrateOldConfig(n||this.createDefaultConfig());if(n?.credential_store!==k&&e(a))try{c=this.mergeLegacySecrets(c,_(a))}catch(e){throw new Error(`Legacy backup credentials could not be decrypted: ${a}`,{cause:e})}this.saveConfig(c)}getConfigDir(){return this.configDir}getBaseUrl(){return this.runtimeBaseUrl||this.config.profiles?.[this.getActiveProfileName()]?.base_url||DEFAULT_BASE_URL}hasRuntimeBaseUrl(){return Boolean(this.runtimeBaseUrl)}setBaseUrl(e,t=!1){this.runtimeBaseUrl=e,t&&this.updateProfile(this.getActiveProfileName(),{base_url:e})}resetBaseUrl(){this.runtimeBaseUrl=void 0;const e=this.config.profiles?.[this.getActiveProfileName()]||{},{base_url:t,...i}=e,o={...this.config.profiles||{},[this.getActiveProfileName()]:i};this.saveConfig({...this.config,profiles:o})}}export const configManager=ConfigManager.getInstance();
1
+ import{existsSync as e,mkdirSync as t,readFileSync as i,writeFileSync as o,renameSync as s,unlinkSync as r,readdirSync as n,rmdirSync as a,statSync as l,chmodSync as c}from"fs";import{join as f,dirname as g}from"path";import{homedir as h}from"os";import{createHash as p}from"crypto";import*as m from"js-yaml";import{logger as u}from"../utils/logger.js";import{getDefaultModels as d,isRetiredDefaultModel as y}from"./model-registry.js";import{readLegacySecretsFile as _}from"./secret-store.js";import{brand as k,brandEnv as b}from"./brand.js";export const DEFAULT_BASE_URL=k().gatewayAddresses[0].url;export const DEFAULT_MODELS=d();export const DEFAULT_PROFILE_NAME="default";const v="plaintext";export class ConfigManager{static instance;configDir;configPath;config;runtimeBaseUrl;constructor(){this.configDir=this.resolveConfigDir(),this.migrateLegacyConfigDir(),this.configPath=f(this.configDir,"config.yaml"),this.config=this.loadConfig()}migrateLegacyConfigDir(){try{const t=f(g(this.configDir),".chelper");if(t===this.configDir||!e(t))return;if(["config.yaml","secrets.enc"].some(t=>e(f(this.configDir,t))))return;if(e(this.configDir)){for(const i of n(t)){const o=f(this.configDir,i);e(o)||s(f(t,i),o)}0===n(t).length&&a(t)}else s(t,this.configDir);u.record(`Migrated config dir: ${t} -> ${this.configDir}`)}catch(e){u.warn("Failed to migrate legacy .chelper config dir:",e)}}resolveConfigDir(){const e=b("CONFIG_DIR");if(e&&e.trim())return e.trim();const t=b("TEST_HOME");return t&&t.trim()?f(t.trim(),k().configDirName):f(h(),k().configDirName)}createDefaultConfig(){return this.syncLegacyFields({lang:"en_US",active_profile:"default",profiles:{[DEFAULT_PROFILE_NAME]:{}},presets:{}})}normalizeModels(e){const t=t=>{const i=e?.[t]?.trim();return i&&!y(t,i)?i:DEFAULT_MODELS[t]},i={haiku:t("haiku"),sonnet:t("sonnet"),opus:t("opus"),reasoning:t("reasoning")};if(e&&"object"==typeof e)for(const[t,o]of Object.entries(e))t in i||"string"==typeof o&&o.trim()&&(i[t]=o.trim());return i}normalizeToolModels(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i={};for(const[e,o]of Object.entries(t))"string"==typeof o&&o.trim()&&(i[e]=o.trim());return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeToolSettings(e){if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||!t||"object"!=typeof t||Array.isArray(t))return[];const i=Object.fromEntries(Object.entries(t).filter(([,e])=>"string"==typeof e||"boolean"==typeof e||"number"==typeof e&&Number.isFinite(e)));return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeStringRecord(e){return!e||"object"!=typeof e||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(e=>"string"==typeof e[1]&&Boolean(e[1].trim())).map(([e,t])=>[e,t.trim()]))}normalizeProfile(e){if(!e)return{};const t=this.normalizeToolModels(e.tool_models),i=this.normalizeToolSettings(e.tool_settings),o=this.normalizeStringRecord(e.tool_api_keys);return{..."string"==typeof e.api_key&&e.api_key?{api_key:e.api_key}:{},...Object.keys(o).length>0?{tool_api_keys:o}:{},..."string"==typeof e.base_url&&e.base_url?{base_url:e.base_url}:{},...e.models?{models:this.normalizeModels(e.models)}:{},...Object.keys(t).length>0?{tool_models:t}:{},...Object.keys(i).length>0?{tool_settings:i}:{}}}normalizeProfiles(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>e&&"string"==typeof e&&t&&"object"==typeof t?[[e,this.normalizeProfile(t)]]:[]);return Object.fromEntries(t)}normalizePresets(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i=t;return i.models?[[e,{models:this.normalizeModels(i.models),updated_at:i.updated_at||new Date(0).toISOString()}]]:[]});return Object.fromEntries(t)}getResolvedActiveProfile(e){const t=e.active_profile||"default";return e.profiles?.[t]||{}}syncLegacyFields(e){const t=this.normalizeProfiles(e.profiles),i=e.active_profile?.trim()||Object.keys(t)[0]||"default",o=t[i]?t:{...t,[i]:{}},s=this.getResolvedActiveProfile({...e,profiles:o,active_profile:i});return{...e,lang:e.lang||"en_US",active_profile:i,profiles:o,presets:this.normalizePresets(e.presets),api_key:s.api_key,base_url:s.base_url,models:s.models?this.normalizeModels(s.models):DEFAULT_MODELS}}sanitizeBackupLabel(e){return(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}getBackupDir(){return f(this.configDir,"backups")}getLegacySecretsPath(){return f(this.configDir,"secrets.enc")}getSecretsBackupPath(e){return e.replace(/\.yaml$/,".secrets.enc")}static getInstance(){return ConfigManager.instance||(ConfigManager.instance=new ConfigManager),ConfigManager.instance}ensureConfigDir(){e(this.configDir)||t(this.configDir,{recursive:!0})}loadConfig(){try{if(e(this.configPath)){const t=i(this.configPath,"utf-8"),o=m.load(t);let s=this.migrateOldConfig(o||{lang:"en_US"}),n=!1;const a=this.getLegacySecretsPath();if(e(a)&&o?.credential_store!==v)try{s=this.mergeLegacySecrets(s,_(a)),n=!0}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecrets",e)}if((this.needsMigration(o)||n)&&(this.backupConfig(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(s))),n))try{r(a)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}try{c(this.configPath,384)}catch{}return s}const t=this.getLegacySecretsPath();if(e(t))try{const e=this.mergeLegacySecrets(this.createDefaultConfig(),_(t));this.ensureConfigDir(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(e)));try{r(t)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}return e}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecretsWithoutConfig",e)}}catch(e){u.warn("Failed to load config, using defaults:",e),u.logError("ConfigManager.loadConfig",e)}return this.createDefaultConfig()}needsMigration(e){return!(!e||"object"!=typeof e)&&("plan"in e||!("profiles"in e)||!("active_profile"in e)||!("presets"in e))}migrateOldConfig(e){if(!e||"object"!=typeof e)return this.createDefaultConfig();const t=e,{plan:i,...o}=t,s=this.normalizeProfiles(o.profiles),r=this.normalizeProfile({api_key:"string"==typeof o.api_key?o.api_key:void 0,base_url:"string"==typeof o.base_url?o.base_url:void 0,models:o.models}),n=Object.keys(s).length>0?s:{[DEFAULT_PROFILE_NAME]:r},a="string"==typeof o.active_profile&&o.active_profile.trim()?o.active_profile.trim():Object.keys(n)[0]||"default";return this.syncLegacyFields({lang:"string"==typeof o.lang&&o.lang?o.lang:"en_US",...!0===o.lang_chosen?{lang_chosen:!0}:{},...o.credential_store===v?{credential_store:v}:{},active_profile:a,profiles:n,presets:this.normalizePresets(o.presets)})}atomicWrite(t,i){const n=`${t}.tmp`;try{o(n,i,{encoding:"utf-8",mode:384}),s(n,t);try{c(t,384)}catch{}}catch(t){if(e(n))try{r(n)}catch{}throw t}}backupConfig(){if(!e(this.configPath))return;const s=this.getBackupDir();e(s)||t(s,{recursive:!0});const r=(new Date).toISOString().replace(/[:.]/g,"-"),n=f(s,`config-${r}.yaml`);try{const e=i(this.configPath,"utf-8");o(n,e,{encoding:"utf-8",mode:384}),this.rotateBackups(s,10,30)}catch(e){u.logError("ConfigManager.backupConfig",e)}}rotateBackups(t,i,o){try{const s=Date.now()-24*o*60*60*1e3,a=n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>({name:e,path:f(t,e),mtime:l(f(t,e)).mtime})).sort((e,t)=>t.mtime.getTime()-e.mtime.getTime()),c=new Set;a.slice(i).forEach(e=>c.add(e.path)),a.forEach(e=>{e.mtime.getTime()<s&&c.add(e.path)});for(const t of c){let i=!1;try{r(t),i=!0}catch(e){u.logError("ConfigManager.rotateBackups",e)}if(i){const i=this.getSecretsBackupPath(t);if(e(i))try{r(i)}catch(e){u.logError("ConfigManager.rotateBackups.secrets",e)}}}}catch(e){u.logError("ConfigManager.rotateBackups",e)}}saveConfig(e){try{this.ensureConfigDir(),this.backupConfig();const t=this.syncLegacyFields(this.migrateOldConfig(e||this.config)),i=this.prepareForPersistence(t),o=m.dump(i);this.atomicWrite(this.configPath,o),this.config=t}catch(e){throw u.error("Failed to save config:",e),u.logError("ConfigManager.saveConfig",e),e}}prepareForPersistence(e){const t={...e,credential_store:v};return delete t.api_key,delete t.base_url,delete t.models,t}mergeLegacySecrets(e,t){const i={...e.profiles||{}},o=new Set([...Object.keys(t.api_keys||{}),...Object.keys(t.tool_api_keys||{})]);for(const e of o){const o=i[e]||{},s=o.api_key||t.api_keys?.[e],r={...t.tool_api_keys?.[e]||{},...o.tool_api_keys||{}};i[e]={...o,...s?{api_key:s}:{},...Object.keys(r).length>0?{tool_api_keys:r}:{}}}return this.syncLegacyFields({...e,profiles:i})}getConfig(){return this.syncLegacyFields({...this.config})}updateConfig(e){this.saveConfig({...this.config,...e})}isFirstRun(){return!e(this.configPath)}getLang(){return this.config.lang||"en_US"}isLangChosen(){return!0===this.config.lang_chosen}setLang(e){this.updateConfig({lang:e,lang_chosen:!0})}getActiveProfileName(){return this.config.active_profile||"default"}listProfiles(){return Object.keys(this.config.profiles||{}).sort()}getProfile(e=this.getActiveProfileName()){const t=this.config.profiles?.[e]||{};return{...t.api_key?{api_key:t.api_key}:{},...t.tool_api_keys&&Object.keys(t.tool_api_keys).length>0?{tool_api_keys:this.normalizeStringRecord(t.tool_api_keys)}:{},...t.base_url?{base_url:t.base_url}:{},models:t.models?this.normalizeModels(t.models):DEFAULT_MODELS,...t.tool_models&&Object.keys(t.tool_models).length>0?{tool_models:this.normalizeToolModels(t.tool_models)}:{},...t.tool_settings&&Object.keys(t.tool_settings).length>0?{tool_settings:this.normalizeToolSettings(t.tool_settings)}:{}}}createProfile(e,t=this.getActiveProfileName()){const i=this.getProfile(t),o={...this.config.profiles||{},[e]:{...i.api_key?{api_key:i.api_key}:{},...i.base_url?{base_url:i.base_url}:{},models:this.normalizeModels(i.models)}};this.saveConfig({...this.config,profiles:o})}setActiveProfile(e){if(!this.config.profiles?.[e])throw new Error(`Profile not found: ${e}`);this.saveConfig({...this.config,active_profile:e})}updateProfile(e,t){const i=this.config.profiles?.[e]||{},o=t.models?this.normalizeModels({...i.models,...t.models}):i.models?this.normalizeModels(i.models):void 0,s={...i,...void 0!==t.api_key?{api_key:t.api_key}:{},...void 0!==t.base_url?{base_url:t.base_url}:{},...o?{models:o}:{}},r={...this.config.profiles||{},[e]:s};this.saveConfig({...this.config,profiles:r})}deleteProfile(e){const t={...this.config.profiles||{}};if(!t[e])return;const i=Object.keys(t).filter(t=>t!==e);if(0===i.length)throw new Error("At least one profile must remain");delete t[e];const o=this.getActiveProfileName()===e?i[0]:this.getActiveProfileName();this.saveConfig({...this.config,profiles:t,active_profile:o})}getApiKey(){return this.config.profiles?.[this.getActiveProfileName()]?.api_key}setApiKey(e){this.updateProfile(this.getActiveProfileName(),{api_key:e})}revokeApiKey(){const e=this.config.profiles?.[this.getActiveProfileName()]||{},{api_key:t,tool_api_keys:i,...o}=e,s={...this.config.profiles||{},[this.getActiveProfileName()]:o};this.saveConfig({...this.config,profiles:s})}getApiKeyFingerprint(){const e=this.getApiKey();return e?p("sha256").update(e).digest("hex").slice(0,12):""}getApiKeyForTool(e){const t=this.config.profiles?.[this.getActiveProfileName()];return t?.tool_api_keys?.[e]||t?.api_key||void 0}setToolApiKey(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...this.config.profiles||{},[i]:{...o,tool_api_keys:{...o.tool_api_keys||{},[e]:t}}};this.saveConfig({...this.config,profiles:s})}clearToolApiKey(e){const t=this.getActiveProfileName(),i=this.config.profiles?.[t]||{},{[e]:o,...s}=i.tool_api_keys||{},r={...i};Object.keys(s).length>0?r.tool_api_keys=s:delete r.tool_api_keys,this.saveConfig({...this.config,profiles:{...this.config.profiles||{},[t]:r}})}listToolApiKeys(){return Object.keys(this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys||{}).sort()}getToolApiKeyFingerprint(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys?.[e];return t?p("sha256").update(t).digest("hex").slice(0,12):""}getModels(){const e=this.config.profiles?.[this.getActiveProfileName()]?.models;return e?this.normalizeModels(e):DEFAULT_MODELS}setModels(e){this.updateProfile(this.getActiveProfileName(),{models:this.normalizeModels(e)})}updateModels(e){this.setModels(this.normalizeModels({...this.getModels(),...e}))}getModelsForTool(e){const t=this.getModels(),i=this.config.profiles?.[this.getActiveProfileName()]?.tool_models?.[e];return i?this.normalizeModels({...t,...i}):t}setToolModel(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...o.tool_models||{}};t&&0!==Object.keys(t).length?s[e]=t:delete s[e];const r={...o};Object.keys(s).length>0?r.tool_models=s:delete r.tool_models;const n={...this.config.profiles||{},[i]:r};this.saveConfig({...this.config,profiles:n})}getToolSettings(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e];return t?{...t}:{}}getToolSetting(e,t){return this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e]?.[t]}setToolSetting(e,t,i){if(this.getToolSetting(e,t)===i)return;const o=this.getActiveProfileName(),s=this.config.profiles?.[o]||{},r={...s.tool_settings||{}};r[e]={...r[e]||{},[t]:i};const n={...this.config.profiles||{},[o]:{...s,tool_settings:r}};this.saveConfig({...this.config,profiles:n})}getCustomPresets(){return{...this.config.presets||{}}}saveCustomPreset(e,t){const i={...this.config.presets||{},[e]:{models:this.normalizeModels(t),updated_at:(new Date).toISOString()}};this.saveConfig({...this.config,presets:i})}deleteCustomPreset(e){const t={...this.config.presets||{}};t[e]&&(delete t[e],this.saveConfig({...this.config,presets:t}))}listBackups(){const t=this.getBackupDir();return e(t)?n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>{const i=f(t,e);return{name:e,path:i,mtimeMs:l(i).mtimeMs}}).sort((e,t)=>t.mtimeMs-e.mtimeMs):[]}createBackup(s){this.ensureConfigDir();const r=this.getBackupDir();e(r)||t(r,{recursive:!0});const n=(new Date).toISOString().replace(/[:.]/g,"-"),a=this.sanitizeBackupLabel(s),l=f(r,a?`config-${n}-${a}.yaml`:`config-${n}.yaml`),c=e(this.configPath)?i(this.configPath,"utf-8"):m.dump(this.prepareForPersistence(this.getConfig()));return o(l,c,{encoding:"utf-8",mode:384}),this.rotateBackups(r,10,30),l}restoreBackup(t){if(!t||"."===t||".."===t||/[/\\]|\.\./.test(t))throw new Error(`Invalid backup name: ${t}`);const o=this.getBackupDir(),s=f(o,t);if(!e(s))throw new Error(`Backup not found: ${t}`);const r=i(s,"utf-8"),n=m.load(r),a=this.getSecretsBackupPath(s);let l=this.migrateOldConfig(n||this.createDefaultConfig());if(n?.credential_store!==v&&e(a))try{l=this.mergeLegacySecrets(l,_(a))}catch(e){throw new Error(`Legacy backup credentials could not be decrypted: ${a}`,{cause:e})}this.saveConfig(l)}getConfigDir(){return this.configDir}getBaseUrl(){return this.runtimeBaseUrl||this.config.profiles?.[this.getActiveProfileName()]?.base_url||DEFAULT_BASE_URL}hasRuntimeBaseUrl(){return Boolean(this.runtimeBaseUrl)}setBaseUrl(e,t=!1){this.runtimeBaseUrl=e,t&&this.updateProfile(this.getActiveProfileName(),{base_url:e})}resetBaseUrl(){this.runtimeBaseUrl=void 0;const e=this.config.profiles?.[this.getActiveProfileName()]||{},{base_url:t,...i}=e,o={...this.config.profiles||{},[this.getActiveProfileName()]:i};this.saveConfig({...this.config,profiles:o})}}export const configManager=ConfigManager.getInstance();
@@ -1,16 +1,16 @@
1
- export type VibeCliErrorType = 'operation' | 'usage' | 'authentication' | 'network' | 'internal' | 'confirmation' | 'cancelled';
2
- export declare const EXIT_CODES: Record<VibeCliErrorType, number>;
3
- export declare class VibeCliError extends Error {
4
- readonly type: VibeCliErrorType;
1
+ export type CliErrorType = 'operation' | 'usage' | 'authentication' | 'network' | 'internal' | 'confirmation' | 'cancelled';
2
+ export declare const EXIT_CODES: Record<CliErrorType, number>;
3
+ export declare class CliError extends Error {
4
+ readonly type: CliErrorType;
5
5
  readonly hint: string;
6
6
  readonly subtype?: string;
7
- constructor(type: VibeCliErrorType, message: string, hint: string, subtype?: string);
7
+ constructor(type: CliErrorType, message: string, hint: string, subtype?: string);
8
8
  }
9
9
  export declare function exitCodeForError(error: unknown): number;
10
- export declare function asVibeCliError(error: unknown): VibeCliError;
10
+ export declare function asCliError(error: unknown): CliError;
11
11
  /** Print the one stable error envelope used by every CLI entry point. */
12
12
  export declare function reportCliError(error: unknown): number;
13
- export declare function usageError(message: string, hint: string, subtype?: string): VibeCliError;
14
- export declare function operationError(message: string, hint: string, subtype?: string): VibeCliError;
15
- export declare function authenticationError(message: string, hint: string, subtype?: string): VibeCliError;
16
- export declare function networkError(message: string, hint: string, subtype?: string): VibeCliError;
13
+ export declare function usageError(message: string, hint: string, subtype?: string): CliError;
14
+ export declare function operationError(message: string, hint: string, subtype?: string): CliError;
15
+ export declare function authenticationError(message: string, hint: string, subtype?: string): CliError;
16
+ export declare function networkError(message: string, hint: string, subtype?: string): CliError;
@@ -1 +1 @@
1
- import r from"chalk";import{i18n as e}from"./i18n.js";import{isColorEnabled as t,isJsonMode as o}from"./runtime-options.js";export const EXIT_CODES={operation:1,usage:2,authentication:3,network:4,internal:5,confirmation:10,cancelled:130};export class VibeCliError extends Error{type;hint;subtype;constructor(r,e,t,o){super(e),this.name="VibeCliError",this.type=r,this.hint=t,this.subtype=o}}export function exitCodeForError(r){return r instanceof VibeCliError?EXIT_CODES[r.type]:EXIT_CODES.internal}export function asVibeCliError(r){if(r instanceof VibeCliError)return r;if("ExitPromptError"===r?.name)return new VibeCliError("cancelled",e.t("errors.cancelled"),e.t("errors.cancel_hint"),"user_cancelled");const t=r instanceof Error?r.message:String(r);return new VibeCliError("internal",t,e.t("errors.hint_logs"),"unexpected_error")}export function reportCliError(e){const n=asVibeCliError(e),i={ok:!1,error:{type:n.type,message:n.message,hint:n.hint,...n.subtype?{subtype:n.subtype}:{}}};if(o())process.stderr.write(JSON.stringify(i)+"\n");else{const e=t()?r.red:r=>r;process.stderr.write(e(n.message)+"\n"+n.hint+"\n")}const s=exitCodeForError(n);return process.exitCode=s,s}export function usageError(r,e,t){return new VibeCliError("usage",r,e,t)}export function operationError(r,e,t){return new VibeCliError("operation",r,e,t)}export function authenticationError(r,e,t){return new VibeCliError("authentication",r,e,t)}export function networkError(r,e,t){return new VibeCliError("network",r,e,t)}
1
+ import r from"chalk";import{i18n as e}from"./i18n.js";import{isColorEnabled as t,isJsonMode as o}from"./runtime-options.js";export const EXIT_CODES={operation:1,usage:2,authentication:3,network:4,internal:5,confirmation:10,cancelled:130};export class CliError extends Error{type;hint;subtype;constructor(r,e,t,o){super(e),this.name="CliError",this.type=r,this.hint=t,this.subtype=o}}export function exitCodeForError(r){return r instanceof CliError?EXIT_CODES[r.type]:EXIT_CODES.internal}export function asCliError(r){if(r instanceof CliError)return r;if("ExitPromptError"===r?.name)return new CliError("cancelled",e.t("errors.cancelled"),e.t("errors.cancel_hint"),"user_cancelled");const t=r instanceof Error?r.message:String(r);return new CliError("internal",t,e.t("errors.hint_logs"),"unexpected_error")}export function reportCliError(e){const n=asCliError(e),i={ok:!1,error:{type:n.type,message:n.message,hint:n.hint,...n.subtype?{subtype:n.subtype}:{}}};if(o())process.stderr.write(JSON.stringify(i)+"\n");else{const e=t()?r.red:r=>r;process.stderr.write(e(n.message)+"\n"+n.hint+"\n")}const s=exitCodeForError(n);return process.exitCode=s,s}export function usageError(r,e,t){return new CliError("usage",r,e,t)}export function operationError(r,e,t){return new CliError("operation",r,e,t)}export function authenticationError(r,e,t){return new CliError("authentication",r,e,t)}export function networkError(r,e,t){return new CliError("network",r,e,t)}
@@ -1 +1 @@
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;for(const e of Object.values(r).flat()){const i=e.clients?.[t];void 0===i||s.has(e.id)||s.set(e.id,i)}for(const[e,t]of s)t||d.add(e);const c=new Map(("claude-code"===t?o:n).map(e=>[e.id,e])),l=(r.gemini??[]).filter(e=>s.get(e.id)??!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.get(e.id)??c.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=>e.clients?.["claude-code"]??t.get(e.id)?.claudeCode??!0)}(r,c)).filter(e=>!(e=>!1===s.get(e.id))(e));if(0===a.length)return n.filter(e=>!d.has(e.id));const u=new Set,f=[];for(const e of a){if(u.has(e.id))continue;u.add(e.id);const{clients:t,minVibecliVersion:i,rolloutPercent:o,...n}=e,d={...c.get(e.id),...n};void 0!==t?.codex&&(d.codex=t.codex),void 0!==t?.["claude-code"]&&(d.claudeCode=t["claude-code"]),f.push(d)}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}(f,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
+ 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;for(const e of Object.values(r).flat()){const i=e.clients?.[t];void 0===i||s.has(e.id)||s.set(e.id,i)}for(const[e,t]of s)t||d.add(e);const l=new Map(("claude-code"===t?o:n).map(e=>[e.id,e])),c=(r.gemini??[]).filter(e=>s.get(e.id)??!1!==o.find(t=>t.id===e.id)?.codex),a=("grok"===t?r.grok??[]:"codex"===t?[...r.codex??[],...c,...(r.claude??[]).filter(e=>e.id.startsWith("claude-")&&(s.get(e.id)??l.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=>e.clients?.["claude-code"]??t.get(e.id)?.claudeCode??!0)}(r,l)).filter(e=>!(e=>!1===s.get(e.id))(e));if(0===a.length)return n.filter(e=>!d.has(e.id));const u=new Set,f=[];for(const e of a){if(u.has(e.id))continue;u.add(e.id);const{clients:t,minClientVersion:i,rolloutPercent:o,...n}=e,d={...l.get(e.id),...n};void 0!==t?.codex&&(d.codex=t.codex),void 0!==t?.["claude-code"]&&(d.claudeCode=t["claude-code"]),f.push(d)}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}(f,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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Names fixed by the gateway's API (New API `controller/vibecode_*.go`). They are part of the wire
3
+ * format every site serves, not branding, so a white-label build keeps them; the package leak check
4
+ * (`scripts/brands.mjs`) allows them in this module only — keep every such name here.
5
+ */
6
+ /** Client configuration for the coding tools (models, defaults, rollout). */
7
+ export declare const CLIENT_CONFIG_PATH = "/api/platform/vibecode/config";
8
+ /** Per-key group and group-model table. */
9
+ export declare const KEY_INFO_PATH = "/api/platform/vibecode/key";
10
+ /** Section of the client configuration that belongs to this CLI. */
11
+ export declare const CLIENT_SECTION = "vibecli";
12
+ /** Model-row field: lowest CLI version that may see the row. */
13
+ export declare const MIN_CLIENT_VERSION = "min_vibecli_version";
@@ -0,0 +1 @@
1
+ export const CLIENT_CONFIG_PATH="/api/platform/vibecode/config";export const KEY_INFO_PATH="/api/platform/vibecode/key";export const CLIENT_SECTION="vibecli";export const MIN_CLIENT_VERSION="min_vibecli_version";
package/dist/lib/i18n.js CHANGED
@@ -1 +1 @@
1
- import{readFileSync as t,existsSync as e,readdirSync as s}from"fs";import{join as o,dirname as a}from"path";import{fileURLToPath as r}from"url";import{logger as n}from"../utils/logger.js";class l{static instance;currentLocale="en_US";translations=new Map;fallbackLocale="en_US";localesDir;constructor(){const t=r(import.meta.url),e=a(t);this.localesDir=o(e,"..","locales"),this.loadTranslations(),this.loadSavedLocale()}static getInstance(){return l.instance||(l.instance=new l),l.instance}loadTranslations(){try{if(!e(this.localesDir))return void n.warn(`Locales directory not found at ${this.localesDir}`);const a=s(this.localesDir).filter(t=>t.endsWith(".json"));if(0===a.length)return void n.warn("No locale files found in locales directory");for(const e of a){const s=e.replace(".json",""),a=o(this.localesDir,e);try{const e=t(a,"utf-8"),o=JSON.parse(e);this.translations.set(s,o)}catch(t){n.warn(`Failed to load locale file ${e}:`,t)}}const r=process.env.LANG||process.env.LC_ALL||process.env.LC_MESSAGES;if(r){const t=r.split(".")[0].replace("_","-");if(this.translations.has(t))this.currentLocale=t;else{const e=t.split("-")[0],s=Array.from(this.translations.keys()).find(t=>t.startsWith(e+"_"));s?this.currentLocale=s:"zh"===e?this.currentLocale="zh_CN":"en"===e&&(this.currentLocale="en_US")}}}catch(t){n.warn("Failed to load translations:",t)}}setLocale(t){this.translations.has(t)?(this.currentLocale=t,this.saveLocale()):n.warn(`Locale '${t}' not supported, falling back to '${this.currentLocale}'`)}getLocale(){return this.currentLocale}getAvailableLocales(){return Array.from(this.translations.keys())}translate(t,e){const s=t.split(".");let o=this.translations.get(this.currentLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o)){o=this.translations.get(this.fallbackLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o))return t;o=o[e]}break}o=o[e]}return"string"!=typeof o?t:e?o.replace(/\{\{(\w+)\}\}/g,(t,s)=>e[s]||t):o}t(t,e){return this.translate(t,e)}saveLocale(){}loadSavedLocale(){}loadFromConfig(t){this.translations.has(t)&&(this.currentLocale=t)}}export function detectSystemLang(){const t=process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||process.env.LANGUAGE||"";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().locale||""}catch{}return`${t} ${e}`.toLowerCase().split(/[\s:;,]+/).some(t=>"zh"===t||t.startsWith("zh-")||t.startsWith("zh_"))?"zh_CN":"en_US"}export{l as I18n};export const i18n=l.getInstance();
1
+ import{readFileSync as t,existsSync as e,readdirSync as s}from"fs";import{join as o,dirname as r}from"path";import{fileURLToPath as a}from"url";import{logger as n}from"../utils/logger.js";import{brandTokens as l}from"./brand.js";class c{static instance;currentLocale="en_US";translations=new Map;fallbackLocale="en_US";localesDir;constructor(){const t=a(import.meta.url),e=r(t);this.localesDir=o(e,"..","locales"),this.loadTranslations(),this.loadSavedLocale()}static getInstance(){return c.instance||(c.instance=new c),c.instance}loadTranslations(){try{if(!e(this.localesDir))return void n.warn(`Locales directory not found at ${this.localesDir}`);const r=s(this.localesDir).filter(t=>t.endsWith(".json"));if(0===r.length)return void n.warn("No locale files found in locales directory");for(const e of r){const s=e.replace(".json",""),r=o(this.localesDir,e);try{const e=t(r,"utf-8"),o=JSON.parse(e);this.translations.set(s,o)}catch(t){n.warn(`Failed to load locale file ${e}:`,t)}}const a=process.env.LANG||process.env.LC_ALL||process.env.LC_MESSAGES;if(a){const t=a.split(".")[0].replace("_","-");if(this.translations.has(t))this.currentLocale=t;else{const e=t.split("-")[0],s=Array.from(this.translations.keys()).find(t=>t.startsWith(e+"_"));s?this.currentLocale=s:"zh"===e?this.currentLocale="zh_CN":"en"===e&&(this.currentLocale="en_US")}}}catch(t){n.warn("Failed to load translations:",t)}}setLocale(t){this.translations.has(t)?(this.currentLocale=t,this.saveLocale()):n.warn(`Locale '${t}' not supported, falling back to '${this.currentLocale}'`)}getLocale(){return this.currentLocale}getAvailableLocales(){return Array.from(this.translations.keys())}translate(t,e){const s=t.split(".");let o=this.translations.get(this.currentLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o)){o=this.translations.get(this.fallbackLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o))return t;o=o[e]}break}o=o[e]}if("string"!=typeof o)return t;const r=l(this.currentLocale);return o=o.replace(/\{\{(\w+)\}\}/g,(t,e)=>r[e]??t),e?o.replace(/\{\{(\w+)\}\}/g,(t,s)=>e[s]||t):o}t(t,e){return this.translate(t,e)}saveLocale(){}loadSavedLocale(){}loadFromConfig(t){this.translations.has(t)&&(this.currentLocale=t)}}export function detectSystemLang(){const t=process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||process.env.LANGUAGE||"";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().locale||""}catch{}return`${t} ${e}`.toLowerCase().split(/[\s:;,]+/).some(t=>"zh"===t||t.startsWith("zh-")||t.startsWith("zh_"))?"zh_CN":"en_US"}export{c as I18n};export const i18n=c.getInstance();