@vibeapi/cli 0.0.33 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,14 @@ npm install -g @vibeapi/cli # 或全局安装后用 vibecli
16
16
 
17
17
  > `@vibeapi/cli` 与 `@vibeapi/api-helper` 是同一产物的双包名(同版本等价),装哪个都一样。
18
18
 
19
+ npmjs.com 不可用时,可直接从 CNB 备用制品库启动:
20
+
21
+ ```bash
22
+ npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@latest
23
+ ```
24
+
25
+ 全局安装的 `vibecli` 每次启动都会进入自动更新预检(6 小时内复用缓存),固定按 **CNB → npmjs → npmmirror → 华为云** 查询和安装;检测到新版会自动升级并重新执行当前命令。网络或权限错误不会阻断原命令,每个安装源最长等待 45 秒,安装失败后 1 小时内不重复打扰。设置 `VIBECLI_DISABLE_AUTO_UPDATE=1` 可关闭启动更新。`npx @latest` 在 CLI 启动前由 npm 解析,因此首次下载失败时请使用上面的 CNB 命令。
26
+
19
27
  ## 快速开始
20
28
 
21
29
  ```bash
@@ -58,7 +66,7 @@ vibecli doctor # 健康巡检
58
66
 
59
67
  ## 支持
60
68
 
61
- 主页 <https://www.vibeapi.cn/> · 反馈 <https://www.vibeapi.cn/support>
69
+ 主页 <https://www.vibeapi.cn/> · 反馈 <https://www.vibeapi.cn/support> · [CNB 备用制品库](https://cnb.cool/vibeapi/npm/-/registries/@vibeapi/cli)
62
70
 
63
71
  ## License
64
72
 
@@ -1,7 +1,39 @@
1
- interface UpdateOptions {
1
+ export declare const UPDATE_TIMEOUT_MS = 1500;
2
+ export interface LocalPackageInfo {
3
+ name: string;
4
+ version: string;
5
+ root: string;
6
+ }
7
+ export type UpdateSourceId = 'cnb' | 'npm' | 'npmmirror' | 'huawei';
8
+ export interface UpdateSource {
9
+ id: UpdateSourceId;
10
+ registry: string;
11
+ metadataUrl: (packageName: string) => string;
12
+ readVersion: (metadata: Record<string, unknown>) => string | null;
13
+ }
14
+ export interface UpdateSourceError {
15
+ source: UpdateSourceId;
16
+ error: string;
17
+ }
18
+ export interface UpdateCheckResult {
19
+ current: string;
20
+ latest: string | null;
21
+ up_to_date: boolean | null;
22
+ source: UpdateSourceId | null;
23
+ registry: string | null;
24
+ errors: UpdateSourceError[];
25
+ error: string | null;
26
+ }
27
+ export interface UpdateOptions {
2
28
  fetchFn?: typeof fetch;
29
+ localPackage?: LocalPackageInfo;
3
30
  localVersion?: string;
31
+ packageName?: string;
32
+ timeoutMs?: number;
33
+ sources?: readonly UpdateSource[];
4
34
  }
35
+ export declare const UPDATE_SOURCES: readonly UpdateSource[];
36
+ export declare function readLocalPackage(): LocalPackageInfo;
5
37
  export declare function compareSemver(a: string, b: string): number;
38
+ export declare function checkForUpdate(options?: UpdateOptions): Promise<UpdateCheckResult>;
6
39
  export declare function updateCommand(options?: UpdateOptions): Promise<void>;
7
- export {};
@@ -1 +1 @@
1
- import t from"chalk";import{readFileSync as e}from"fs";import{join as r,dirname as n}from"path";import{fileURLToPath as o}from"url";import{i18n as i}from"../lib/i18n.js";import{isJsonMode as a,emitJson as l,isColorEnabled as s}from"../lib/runtime-options.js";function p(t){return s()?t:t=>t}function c(t){const[e,...r]=t.split("-"),n=r.length?r.join("-").split("."):[];return{main:e.split(".").map(t=>Number.parseInt(t,10)||0),pre:n}}function u(t,e){const r=Number.parseInt(t,10),n=Number.parseInt(e,10),o=Number.isFinite(r)&&String(r)===t,i=Number.isFinite(n)&&String(n)===e;return o&&i?r-n:o?-1:i?1:t<e?-1:t>e?1:0}export function compareSemver(t,e){const r=c(t),n=c(e),o=Math.max(r.main.length,n.main.length);for(let t=0;t<o;t+=1){const e=(r.main[t]||0)-(n.main[t]||0);if(0!==e)return e}if(0===r.pre.length&&0===n.pre.length)return 0;if(0===r.pre.length)return 1;if(0===n.pre.length)return-1;const i=Math.max(r.pre.length,n.pre.length);for(let t=0;t<i;t+=1){const e=r.pre[t],o=n.pre[t];if(void 0===e)return-1;if(void 0===o)return 1;const i=u(e,o);if(0!==i)return i}return 0}export async function updateCommand(s={}){const c=s.fetchFn||fetch,u=s.localVersion||function(){try{const t=o(import.meta.url),i=n(t),a=r(i,"../../package.json");return JSON.parse(e(a,"utf-8")).version||"0.0.0"}catch{return"0.0.0"}}();a()||console.log(p(t.gray)(i.t("update.checking")));let m=null,f=null;try{const t=await c("https://registry.npmjs.org/@vibeapi/api-helper/latest",{headers:{Accept:"application/json"}});t.ok?m=(await t.json()).version||null:f=`HTTP ${t.status}`}catch(t){f=t instanceof Error?t.message:String(t)}a()?l({current:u,latest:m,up_to_date:m?compareSemver(u,m)>=0:null,error:f}):(console.log(` ${p(t.cyan)(i.t("update.current",{version:u}))}`),m?(console.log(` ${p(t.cyan)(i.t("update.latest",{version:m}))}`),compareSemver(u,m)>=0?console.log(" "+p(t.green)(i.t("update.up_to_date"))):(console.log(" "+p(t.yellow)(i.t("update.available"))),console.log(" "+p(t.gray)(i.t("update.command_hint"))))):console.log(" "+p(t.yellow)(i.t("update.fetch_failed",{error:f||"unknown"}))))}
1
+ import r from"chalk";import{readFileSync as t}from"fs";import{join as e,dirname as o}from"path";import{fileURLToPath as n}from"url";import{i18n as a}from"../lib/i18n.js";import{isJsonMode as s,emitJson as i,isColorEnabled as c}from"../lib/runtime-options.js";const l="@vibeapi/api-helper";export const UPDATE_TIMEOUT_MS=1500;const p=(r,t,e="")=>`${r}${encodeURIComponent(t)}${e}`,u=r=>{const t=r["dist-tags"];if(!t||"object"!=typeof t)return null;const e=t.latest;return"string"==typeof e?e:null};export const UPDATE_SOURCES=[{id:"cnb",registry:"https://npm.cnb.cool/vibeapi/npm/-/packages/",metadataUrl:r=>p("https://npm.cnb.cool/vibeapi/npm/-/packages/",r),readVersion:u},{id:"npm",registry:"https://registry.npmjs.org/",metadataUrl:r=>p("https://registry.npmjs.org/",r),readVersion:u},{id:"npmmirror",registry:"https://registry.npmmirror.com/",metadataUrl:r=>p("https://registry.npmmirror.com/",r),readVersion:u},{id:"huawei",registry:"https://repo.huaweicloud.com/repository/npm/",metadataUrl:r=>p("https://repo.huaweicloud.com/repository/npm/",r),readVersion:u}];function m(r){return c()?r:r=>r}export function readLocalPackage(){const r=n(import.meta.url),a=o(r),s=e(a,"..","..");try{const r=JSON.parse(t(e(s,"package.json"),"utf-8"));return{name:r.name||l,version:r.version||"0.0.0",root:s}}catch{return{name:l,version:"0.0.0",root:s}}}function g(r){const[t,...e]=r.split("-"),o=e.length?e.join("-").split("."):[];return{main:t.split(".").map(r=>Number.parseInt(r,10)||0),pre:o}}function d(r,t){const e=Number.parseInt(r,10),o=Number.parseInt(t,10),n=Number.isFinite(e)&&String(e)===r,a=Number.isFinite(o)&&String(o)===t;return n&&a?e-o:n?-1:a?1:r<t?-1:r>t?1:0}export function compareSemver(r,t){const e=g(r),o=g(t),n=Math.max(e.main.length,o.main.length);for(let r=0;r<n;r+=1){const t=(e.main[r]||0)-(o.main[r]||0);if(0!==t)return t}if(0===e.pre.length&&0===o.pre.length)return 0;if(0===e.pre.length)return 1;if(0===o.pre.length)return-1;const a=Math.max(e.pre.length,o.pre.length);for(let r=0;r<a;r+=1){const t=e.pre[r],n=o.pre[r];if(void 0===t)return-1;if(void 0===n)return 1;const a=d(t,n);if(0!==a)return a}return 0}async function f(r,t,e,o){const n=new AbortController,a=setTimeout(()=>n.abort(),o);try{const o=await e(r.metadataUrl(t),{headers:{Accept:"application/json"},signal:n.signal});if(!o.ok)throw new Error(`HTTP ${o.status}`);const a=await o.json(),s=r.readVersion(a);if(!s)throw new Error("invalid registry metadata");return s}catch(r){if(n.signal.aborted)throw new Error(`timeout after ${o}ms`);throw r}finally{clearTimeout(a)}}export async function checkForUpdate(r={}){const t=r.localPackage||readLocalPackage(),e=r.localVersion||t.version,o=r.packageName||t.name,n=r.fetchFn||fetch,a=r.timeoutMs||1500,s=r.sources||UPDATE_SOURCES,i=[];for(const r of s)try{const t=await f(r,o,n,a);return{current:e,latest:t,up_to_date:compareSemver(e,t)>=0,source:r.id,registry:r.registry,errors:i,error:null}}catch(t){i.push({source:r.id,error:t instanceof Error?t.message:String(t)})}return{current:e,latest:null,up_to_date:null,source:null,registry:null,errors:i,error:i.map(r=>`${r.source}: ${r.error}`).join("; ")||"unknown"}}export async function updateCommand(t={}){const e=t.localPackage||readLocalPackage();s()||console.log(m(r.gray)(a.t("update.checking")));const o=await checkForUpdate({...t,localPackage:e});if(s())i(o);else if(console.log(` ${m(r.cyan)(a.t("update.current",{version:o.current}))}`),o.latest)if(console.log(` ${m(r.cyan)(a.t("update.latest",{version:o.latest}))}`),console.log(` ${m(r.cyan)(a.t("update.source",{source:o.source||"unknown"}))}`),o.up_to_date)console.log(" "+m(r.green)(a.t("update.up_to_date")));else{const t="npm"===o.source?"":` --registry ${o.registry}`,n=`npm install -g ${e.name}@latest${t}`;console.log(" "+m(r.yellow)(a.t("update.available"))),console.log(" "+m(r.gray)(a.t("update.command_hint",{command:n})))}else console.log(" "+m(r.yellow)(a.t("update.fetch_failed",{error:o.error||"unknown"})))}
@@ -0,0 +1,34 @@
1
+ import { type LocalPackageInfo, type UpdateCheckResult } from '../commands/update.js';
2
+ export declare const UPDATE_CHECK_INTERVAL_MS: number;
3
+ export declare const INSTALL_RETRY_INTERVAL_MS: number;
4
+ export declare const INSTALL_TIMEOUT_MS = 45000;
5
+ interface RunnerResult {
6
+ status: number | null;
7
+ error?: Error;
8
+ }
9
+ export interface StartupUpdateOptions {
10
+ env?: NodeJS.ProcessEnv;
11
+ localPackage?: LocalPackageInfo;
12
+ globalInstall?: boolean;
13
+ npx?: boolean;
14
+ now?: number;
15
+ cachePath?: string;
16
+ fetchFn?: typeof fetch;
17
+ installRunner?: (command: string, args: string[]) => RunnerResult;
18
+ reexecRunner?: (args: string[], env: NodeJS.ProcessEnv) => RunnerResult;
19
+ output?: (message: string) => void;
20
+ errorOutput?: (message: string) => void;
21
+ }
22
+ export interface StartupUpdateResult {
23
+ status: 'skipped' | 'current' | 'unavailable' | 'update_failed' | 'reexecuted';
24
+ handled: boolean;
25
+ source: UpdateCheckResult['source'];
26
+ }
27
+ export declare function resolveUpdateCachePath(env?: NodeJS.ProcessEnv): string;
28
+ export declare function isGlobalPackageInstall(root: string): boolean;
29
+ export declare function isNpxExecution(env?: NodeJS.ProcessEnv): boolean;
30
+ export declare function isPnpmGlobalInstall(root: string): boolean;
31
+ export declare function resolveNpmGlobalPrefix(root: string): string | null;
32
+ export declare function shouldSkipStartupUpdate(args: string[], env?: NodeJS.ProcessEnv): boolean;
33
+ export declare function runStartupUpdate(args: string[], options?: StartupUpdateOptions): Promise<StartupUpdateResult>;
34
+ export {};
@@ -0,0 +1 @@
1
+ import{chmodSync as e,existsSync as t,mkdirSync as r,readFileSync as n,renameSync as s,writeFileSync as o}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";export const UPDATE_CHECK_INTERVAL_MS=216e5;export const INSTALL_RETRY_INTERVAL_MS=36e5;export const INSTALL_TIMEOUT_MS=45e3;function v(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))||e.includes("update")||e.includes("completion"))}function I(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}};o(c,JSON.stringify(p),{encoding:"utf-8",mode:384}),s(c,t),e(t,384)}catch(e){x.warn("Failed to persist update check cache:",e)}}const y=(e,t)=>c(e,t,{stdio:"inherit",timeout:45e3,killSignal:"SIGTERM"}),E=(e,t)=>c(process.execPath,[process.argv[1],...e],{stdio:"inherit",env:t});export async function runStartupUpdate(e,r={}){const s=r.env||process.env,o=r.localPackage||f(),a=r.globalInstall??isGlobalPackageInstall(o.root),l=r.npx??isNpxExecution(s);if(!a||l||shouldSkipStartupUpdate(e,s))return{status:"skipped",handled:!1,source:null};const i=r.now??Date.now(),u=r.cachePath||resolveUpdateCachePath(s),c=function(e,r,s){try{if(!t(e))return null;const o=JSON.parse(n(e,"utf-8"));if(o.package_name!==r.name||!Number.isFinite(o.checked_at))return null;const a=o.latest?216e5:6e5;return s-o.checked_at>=a?null:{result:{current:r.version,latest:o.latest,up_to_date:o.latest?m(r.version,o.latest)>=0:null,source:o.source,registry:o.registry,errors:Array.isArray(o.errors)?o.errors:[],error:o.latest?null:(o.errors||[]).map(e=>`${e.source}: ${e.error}`).join("; ")||"unknown"},installAttemptedAt:o.latest&&o.install_attempted_version===o.latest&&Number.isFinite(o.install_attempted_at)?o.install_attempted_at:null}}catch{return null}}(u,o,i);let g=c?.result,x=c?.installAttemptedAt||null;if(g||(g=await d({localPackage:o,fetchFn:r.fetchFn}),I(u,o.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 k=r.output||console.log,A=r.errorOutput||console.error,P=r.installRunner||y,S=isPnpmGlobalInstall(o.root),T=S?"win32"===process.platform?"pnpm.cmd":"pnpm":"win32"===process.platform?"npm.cmd":"npm",$=S?null:resolveNpmGlobalPrefix(o.root);k(v(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",`${o.name}@${g.latest}`,"--registry",e]:["install","--global",...$?["--prefix",$]:[],`${o.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 I(u,o.name,i,g,i),A(v(p.yellow,h.t("update.auto_failed",{error:N}))),{status:"update_failed",handled:!1,source:g.source};k(v(p.green,h.t("update.auto_installed",{version:g.latest})));const U=(r.reexecRunner||E)(e,{...s,VIBECLI_SKIP_AUTO_UPDATE:"1"});return U.error?(A(v(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 +1 @@
1
- import{Command as a}from"commander";import{i18n as e,detectSystemLang as o}from"./i18n.js";import{configManager as t}from"./config.js";import{wizard as i}from"./wizard.js";import{langCommand as n,authCommand as s,doctorCommand as r,configCommand as c,statusCommand as m}from"../commands/index.js";import{logsCommand as p}from"../commands/logs.js";import{completionCommand as l}from"../commands/completion.js";import{benchCommand as d}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{setupCommand as u}from"../commands/setup.js";import h from"chalk";import{readFileSync as y}from"fs";import{join as f,dirname as b}from"path";import{fileURLToPath as v}from"url";import{setRuntimeOptions as w,detectColorPreferenceFromEnv as k,isColorEnabled as $,isJsonMode as j}from"./runtime-options.js";import{cleanupAnthropicEnvVars as C}from"./env-cleanup.js";export class Command{program;constructor(){const i=t.isFirstRun()?o():t.getLang();e.loadFromConfig(i),this.program=new a,this.setupProgram()}getVersion(){try{const a=v(import.meta.url),e=b(a),o=f(e,"../../package.json");return JSON.parse(y(o,"utf-8")).version}catch{return"1.0.0"}}setupProgram(){this.program.name("vibecli").description(e.t("cli.title")).version(this.getVersion(),"-v, --version",e.t("commands.version")).helpOption("-h, --help",e.t("commands.help")).option("--base <url>","Custom API base URL").option("--non-interactive","Disable interactive prompts (CI mode)").option("--json","Emit machine-readable JSON output where applicable").option("--yes, -y","Auto-confirm prompts that have a default action").option("--dry-run","Show planned changes without writing anywhere").option("--no-color","Disable colored output"),this.program.command("setup").description(e.t("commands.setup")).option("--key <key>","API key for all capable tools (capability auto-detected)").option("--claudekey <key>","Dedicated API key for Claude Code").option("--codexkey <key>","Dedicated API key for Codex").option("--all","Configure every tool the key can serve (default behavior)").action(async a=>{await u(a)}),this.program.command("init").description(e.t("commands.init")).action(async()=>{await this.handleInitCommand()});const a=this.program.command("lang").description(e.t("commands.lang"));a.command("show").description(e.t("lang.show_usage")).action(async()=>{await n(["show"])}),a.command("set <locale>").description(e.t("lang.set_usage")).action(async a=>{await n(["set",a])});const o=this.program.command("auth").description(e.t("commands.auth"));o.argument("[token]","API token").action(async a=>{const e=[];a&&e.push(a),await s(e)}),o.command("revoke").description("Revoke saved API key").action(async()=>{await s(["revoke"])}),o.command("reload <tool>").description("Reload plan configuration to the specified tool (e.g., claude)").action(async a=>{await s(["reload",a])}),this.program.command("doctor").description(e.t("commands.doctor")).action(async()=>{await r()}),this.program.command("status").description(e.t("commands.status")).action(async()=>{await m()}),this.program.command("logs").description("Inspect vibecli log files").argument("[action]","list|tail|path").argument("[file]","specific log file when using tail").action(async(a,e)=>{const o=[];a&&o.push(a),e&&o.push(e),await p(o)}),this.program.command("completion <shell>").description("Print shell completion script (bash|zsh|fish)").action(async a=>{await l([a])}),this.program.command("update").description("Check for a newer version on npm").action(async()=>{await g()}),this.program.command("bench").description("Benchmark the configured API endpoint").option("--samples <n>","number of samples to send","5").action(async a=>{const e=[];a.samples&&e.push("--samples",a.samples),await d(e)}),this.program.command("config").description("Manage profiles, presets, backups, and per-tool config").argument("[args...]","Subcommand and arguments").allowUnknownOption(!0).action(async a=>{await c(a||[])}),this.program.command("enter [option]").description(e.t("commands.enter")).action(async a=>{if(a)switch(a){case"lang":case"language":await i.configLanguage();break;case"apikey":case"api-key":await i.configApiKey();break;case"models":await i.configModels();break;default:{const e=[a];await c(e);break}}else await i.showMainMenu()}),this.program.action(async()=>{t.isFirstRun()?(console.log(h.cyan(e.t("messages.first_run"))),await i.runFirstTimeSetup()):await i.showMainMenu()}),this.program.configureHelp({sortSubcommands:!0,subcommandTerm:a=>a.name()+" "+a.usage()}),this.program.addHelpText("after",`\n${h.bold(e.t("cli.examples"))}:\n ${h.gray("$ vibecli # Interactive main menu")}\n ${h.gray("$ vibecli init # Run first-time setup wizard")}\n ${h.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${h.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b")}\n ${h.gray("$ vibecli status --json # Machine-readable status")}\n ${h.gray("$ vibecli config profile list")}\n ${h.gray("$ vibecli config profile create work")}\n ${h.gray("$ vibecli config profile use work")}\n ${h.gray("$ vibecli config preset save fast")}\n ${h.gray("$ vibecli config backup create snapshot")}\n ${h.gray("$ vibecli auth <token> --non-interactive")}\n ${h.gray("$ vibecli auth revoke --yes")}\n ${h.gray("$ vibecli logs path")}\n ${h.gray("$ vibecli completion bash")}\n ${h.gray("$ vibecli bench --samples 3")}\n ${h.gray("$ vibecli update")}\n ${h.gray('$ vibecli --base "https://custom.api.com" init # Custom base URL')}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const a=C();if(0===a.length||j())return;const o=e.t("messages.env_vars_cleared",{vars:a.join(", ")});console.log($()?h.yellow(o):o)}preflightArgs(a){const e=e=>a.includes(e),o=!e("--no-color")&&k();let i;w({nonInteractive:e("--non-interactive"),json:e("--json"),yes:e("--yes")||e("-y"),dryRun:e("--dry-run"),color:o}),o||(h.level=0);for(let e=0;e<a.length;e+=1){const o=a[e];if("--base"===o&&a[e+1]){i=a[e+1];break}if(o.startsWith("--base=")){i=o.slice(7);break}}i&&t.setBaseUrl(i)}async execute(a){try{this.preflightArgs(a),this.cleanupLeakedEnvVars(),await this.program.parseAsync(a,{from:"user"})}catch(a){if(a instanceof Error){const o=$()?h.red:a=>a;console.error(o(e.t("cli.error_general")),a.message)}process.exit(1)}}getProgram(){return this.program}}
1
+ import{Command as a}from"commander";import{i18n as e,detectSystemLang as o}from"./i18n.js";import{configManager as t}from"./config.js";import{wizard as i}from"./wizard.js";import{langCommand as n,authCommand as s,doctorCommand as r,configCommand as c,statusCommand as m}from"../commands/index.js";import{logsCommand as p}from"../commands/logs.js";import{completionCommand as l}from"../commands/completion.js";import{benchCommand as d}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{setupCommand as u}from"../commands/setup.js";import h from"chalk";import{readFileSync as f}from"fs";import{join as y,dirname as b}from"path";import{fileURLToPath as v}from"url";import{setRuntimeOptions as w,detectColorPreferenceFromEnv as k,isColorEnabled as $,isJsonMode as j}from"./runtime-options.js";import{cleanupAnthropicEnvVars as C}from"./env-cleanup.js";import{runStartupUpdate as I}from"./auto-update.js";export class Command{program;constructor(){const i=t.isFirstRun()?o():t.getLang();e.loadFromConfig(i),this.program=new a,this.setupProgram()}getVersion(){try{const a=v(import.meta.url),e=b(a),o=y(e,"../../package.json");return JSON.parse(f(o,"utf-8")).version}catch{return"1.0.0"}}setupProgram(){this.program.name("vibecli").description(e.t("cli.title")).version(this.getVersion(),"-v, --version",e.t("commands.version")).helpOption("-h, --help",e.t("commands.help")).option("--base <url>","Custom API base URL").option("--non-interactive","Disable interactive prompts (CI mode)").option("--json","Emit machine-readable JSON output where applicable").option("--yes, -y","Auto-confirm prompts that have a default action").option("--dry-run","Show planned changes without writing anywhere").option("--no-color","Disable colored output"),this.program.command("setup").description(e.t("commands.setup")).option("--key <key>","API key for all capable tools (capability auto-detected)").option("--claudekey <key>","Dedicated API key for Claude Code").option("--codexkey <key>","Dedicated API key for Codex").option("--all","Configure every tool the key can serve (default behavior)").action(async a=>{await u(a)}),this.program.command("init").description(e.t("commands.init")).action(async()=>{await this.handleInitCommand()});const a=this.program.command("lang").description(e.t("commands.lang"));a.command("show").description(e.t("lang.show_usage")).action(async()=>{await n(["show"])}),a.command("set <locale>").description(e.t("lang.set_usage")).action(async a=>{await n(["set",a])});const o=this.program.command("auth").description(e.t("commands.auth"));o.argument("[token]","API token").action(async a=>{const e=[];a&&e.push(a),await s(e)}),o.command("revoke").description("Revoke saved API key").action(async()=>{await s(["revoke"])}),o.command("reload <tool>").description("Reload plan configuration to the specified tool (e.g., claude)").action(async a=>{await s(["reload",a])}),this.program.command("doctor").description(e.t("commands.doctor")).action(async()=>{await r()}),this.program.command("status").description(e.t("commands.status")).action(async()=>{await m()}),this.program.command("logs").description("Inspect vibecli log files").argument("[action]","list|tail|path").argument("[file]","specific log file when using tail").action(async(a,e)=>{const o=[];a&&o.push(a),e&&o.push(e),await p(o)}),this.program.command("completion <shell>").description("Print shell completion script (bash|zsh|fish)").action(async a=>{await l([a])}),this.program.command("update").description("Check for a newer version across CNB and npm mirrors").action(async()=>{await g()}),this.program.command("bench").description("Benchmark the configured API endpoint").option("--samples <n>","number of samples to send","5").action(async a=>{const e=[];a.samples&&e.push("--samples",a.samples),await d(e)}),this.program.command("config").description("Manage profiles, presets, backups, and per-tool config").argument("[args...]","Subcommand and arguments").allowUnknownOption(!0).action(async a=>{await c(a||[])}),this.program.command("enter [option]").description(e.t("commands.enter")).action(async a=>{if(a)switch(a){case"lang":case"language":await i.configLanguage();break;case"apikey":case"api-key":await i.configApiKey();break;case"models":await i.configModels();break;default:{const e=[a];await c(e);break}}else await i.showMainMenu()}),this.program.action(async()=>{t.isFirstRun()?(console.log(h.cyan(e.t("messages.first_run"))),await i.runFirstTimeSetup()):await i.showMainMenu()}),this.program.configureHelp({sortSubcommands:!0,subcommandTerm:a=>a.name()+" "+a.usage()}),this.program.addHelpText("after",`\n${h.bold(e.t("cli.examples"))}:\n ${h.gray("$ vibecli # Interactive main menu")}\n ${h.gray("$ vibecli init # Run first-time setup wizard")}\n ${h.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${h.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b")}\n ${h.gray("$ vibecli status --json # Machine-readable status")}\n ${h.gray("$ vibecli config profile list")}\n ${h.gray("$ vibecli config profile create work")}\n ${h.gray("$ vibecli config profile use work")}\n ${h.gray("$ vibecli config preset save fast")}\n ${h.gray("$ vibecli config backup create snapshot")}\n ${h.gray("$ vibecli auth <token> --non-interactive")}\n ${h.gray("$ vibecli auth revoke --yes")}\n ${h.gray("$ vibecli logs path")}\n ${h.gray("$ vibecli completion bash")}\n ${h.gray("$ vibecli bench --samples 3")}\n ${h.gray("$ vibecli update")}\n ${h.gray('$ vibecli --base "https://custom.api.com" init # Custom base URL')}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const a=C();if(0===a.length||j())return;const o=e.t("messages.env_vars_cleared",{vars:a.join(", ")});console.log($()?h.yellow(o):o)}preflightArgs(a){const e=e=>a.includes(e),o=!e("--no-color")&&k();let i;w({nonInteractive:e("--non-interactive"),json:e("--json"),yes:e("--yes")||e("-y"),dryRun:e("--dry-run"),color:o}),o||(h.level=0);for(let e=0;e<a.length;e+=1){const o=a[e];if("--base"===o&&a[e+1]){i=a[e+1];break}if(o.startsWith("--base=")){i=o.slice(7);break}}i&&t.setBaseUrl(i)}async execute(a){try{if(this.preflightArgs(a),this.cleanupLeakedEnvVars(),(await I(a)).handled)return;await this.program.parseAsync(a,{from:"user"})}catch(a){if(a instanceof Error){const o=$()?h.red:a=>a;console.error(o(e.t("cli.error_general")),a.message)}process.exit(1)}}getProgram(){return this.program}}
@@ -289,10 +289,15 @@
289
289
  "checking": "Checking for updates...",
290
290
  "current": "Current version: {{version}}",
291
291
  "latest": "Latest version: {{version}}",
292
+ "source": "Version source: {{source}}",
292
293
  "up_to_date": "You are on the latest version",
293
294
  "available": "A new version is available",
294
295
  "fetch_failed": "Failed to fetch latest version: {{error}}",
295
- "command_hint": "Run: pnpm add -g @vibeapi/api-helper@latest"
296
+ "command_hint": "Run: {{command}}",
297
+ "auto_installing": "Updating vibecli to {{version}}...",
298
+ "auto_installed": "Updated vibecli to {{version}}; restarting current command...",
299
+ "auto_failed": "Automatic update failed ({{error}}); continuing with the installed version",
300
+ "reexec_failed": "Updated successfully but could not restart ({{error}}); continuing with the current process"
296
301
  },
297
302
  "runtime": {
298
303
  "dry_run_label": "[dry-run]",
@@ -289,10 +289,15 @@
289
289
  "checking": "正在检查更新...",
290
290
  "current": "当前版本: {{version}}",
291
291
  "latest": "最新版本: {{version}}",
292
+ "source": "版本来源: {{source}}",
292
293
  "up_to_date": "您已是最新版本",
293
294
  "available": "存在新版本",
294
295
  "fetch_failed": "获取最新版本失败: {{error}}",
295
- "command_hint": "升级命令: pnpm add -g @vibeapi/api-helper@latest"
296
+ "command_hint": "升级命令: {{command}}",
297
+ "auto_installing": "正在自动升级 vibecli 到 {{version}}...",
298
+ "auto_installed": "vibecli 已升级到 {{version}},正在重新执行当前命令...",
299
+ "auto_failed": "自动升级失败({{error}}),继续使用当前版本",
300
+ "reexec_failed": "升级成功但无法重新启动({{error}}),继续当前进程"
296
301
  },
297
302
  "runtime": {
298
303
  "dry_run_label": "[预演]",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",