@vibeapi/cli 0.0.85 → 0.0.86

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
@@ -1,11 +1,11 @@
1
- # @vibeapi/api-helper
1
+ # VibeCLI(@vibeapi/api-helper)
2
2
 
3
3
  > 一条命令,在 Claude Code / Claude Desktop / Codex / OpenClaw / Hermes / AtomCode / Grok Build / Antigravity CLI 之间统一配置 API Key 与模型。
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@vibeapi/api-helper.svg)](https://www.npmjs.com/package/@vibeapi/api-helper)
6
6
  [![Node](https://img.shields.io/node/v/@vibeapi/api-helper.svg)](https://nodejs.org)
7
7
 
8
- CLI 名:`vibecli`(也可用 `api-helper`)。需要 **Node.js >= 20**。
8
+ 命令名:`vibecli`(也可用 `api-helper`)。需要 **Node.js >= 20**。每个命令的用法、示例和适用场景:`vibecli <命令> --help`,或在线文档 https://docs.vibeapi.cn/zh/docs/coding-tools/commands 。
9
9
 
10
10
  ## 安装 / 运行
11
11
 
@@ -24,13 +24,15 @@ npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@l
24
24
 
25
25
  全局安装的 `vibecli` 每次启动都会进入自动更新预检(6 小时内复用缓存),固定按 **CNB → npmjs → npmmirror → Yarn registry** 查询和安装;检测到新版会自动升级并重新执行当前命令。网络或权限错误不会阻断原命令,每个安装源最长等待 45 秒,安装失败后 1 小时内不重复打扰。设置 `VIBECLI_DISABLE_AUTO_UPDATE=1` 可关闭启动更新。`npx @latest` 在 CLI 启动前由 npm 解析,因此首次下载失败时请使用上面的 CNB 命令。
26
26
 
27
- 还没装编码工具?国内一条命令装好(与官方安装器相同的安装方式,程序从国内镜像下载;再跑一次就是升级):
27
+ 还没装编码工具?国内一条命令装好(与官方安装器相同的安装方式,程序从国内镜像下载;再跑一次就是升级)。Node.js(VibeCLI 需要 20 及以上)和 Git 的脚本先找机器上已有的,有就不装:
28
28
 
29
29
  | 工具 | macOS / Linux | Windows PowerShell |
30
30
  | --------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
31
31
  | Claude Code | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/claude-code.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/claude-code.ps1 \| iex` |
32
32
  | Codex | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/codex.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/codex.ps1 \| iex` |
33
33
  | Antigravity CLI | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/agy.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/agy.ps1 \| iex` |
34
+ | Node.js | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/node.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/node.ps1 \| iex` |
35
+ | Git | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/git.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/git.ps1 \| iex` |
34
36
 
35
37
  ## 快速开始
36
38
 
@@ -120,7 +122,7 @@ vibecli base https://www.vibeapi.si # 或指定一个地址
120
122
  vibecli base default # 网络恢复后回到主站
121
123
  ```
122
124
 
123
- `auto` 按这个优先级尝试,取第一个能用的:`www.vibeapi.cn` → `www.vibeapi.si` → `hk.vibeapi.cn` → `us13-www.vibeapi.cn` → `cf.vibeapi.cn` → `token.nfeyre.top`。网关控制台以后新增的地址会排在这些后面。保存了令牌时,每个地址都用它实际拉一次模型列表,拉得到才算能用;`vibecli base` 每个地址测 3 次取中位数,并标出最快的一个。第一次 `vibecli setup` / `vibecli init` 时主站连不上,也会按同样的顺序自动换到能用的地址。切换后地址保存在当前 profile 里,Claude Code、Codex、Claude 桌面端等已用 vibecli 配置过的工具会一起改过去,以后再运行 `vibecli setup` 也不会改回主站。首次配置时就可以指定:`vibecli setup --key sk-xxx --base https://www.vibeapi.si`。向导主菜单里也有「切换接入地址」。
125
+ `auto` 按这个优先级尝试,取第一个能用的:`www.vibeapi.cn` → `www.vibeapi.si` → `hk.vibeapi.cn` → `us13-www.vibeapi.cn` → `cf.vibeapi.cn` → `token.nfeyre.top`。网关控制台以后新增的地址会排在这些后面。保存了令牌时,每个地址都用它实际拉一次模型列表,拉得到才算能用;`vibecli base` 每个地址测 3 次取中位数,并标出最快的一个。第一次 `vibecli setup` / `vibecli init` 时主站连不上,也会按同样的顺序自动换到能用的地址。切换后地址保存在当前 profile 里,Claude Code、Codex、Claude 桌面端等已用 VibeCLI 配置过的工具会一起改过去,以后再运行 `vibecli setup` 也不会改回主站。首次配置时就可以指定:`vibecli setup --key sk-xxx --base https://www.vibeapi.si`。向导主菜单里也有「切换接入地址」。
124
126
 
125
127
  ## 支持
126
128
 
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- Number(process.versions.node.split(".")[0])<20&&(console.error(`vibecli 需要 Node.js 20 或更高版本,当前是 v${process.versions.node}。\n请安装 Node.js LTS(国内镜像:https://registry.npmmirror.com/binary.html?path=node/ ,或用 nvm install --lts),装好后重开终端再运行。\nvibecli needs Node.js 20 or later (found v${process.versions.node}); install the LTS release and open a new terminal.`),process.exit(1));const{Command:e}=await import("./lib/command.js"),{i18n:r}=await import("./lib/i18n.js"),{logger:o}=await import("./utils/logger.js");try{await(new e).execute(process.argv.slice(2))}catch(e){o.logError("CLI",e),console.error(`${r.t("cli.error_general")}`,e instanceof Error?e.message:String(e)),process.exit(1)}export{};
2
+ Number(process.versions.node.split(".")[0])<20&&(console.error(`VibeCLI 需要 Node.js 20 或更高版本,当前是 v${process.versions.node}。\n请安装 Node.js LTS(国内镜像:https://registry.npmmirror.com/binary.html?path=node/ ,或用 nvm install --lts),装好后重开终端再运行。\nVibeCLI needs Node.js 20 or later (found v${process.versions.node}); install the LTS release and open a new terminal.`),process.exit(1));const{Command:e}=await import("./lib/command.js"),{i18n:r}=await import("./lib/i18n.js"),{logger:o}=await import("./utils/logger.js");try{await(new e).execute(process.argv.slice(2))}catch(e){o.logError("CLI",e),console.error(`${r.t("cli.error_general")}`,e instanceof Error?e.message:String(e)),process.exit(1)}export{};
@@ -1 +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
+ 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})}
@@ -0,0 +1,57 @@
1
+ import type { Argument, Command, HelpConfiguration, Option } from 'commander';
2
+ /**
3
+ * Help text that commander does not model itself (extra sections such as the
4
+ * subcommands `config` parses on its own, examples, the docs link) is kept as
5
+ * data on each command, so `--help` and the generated docs/commands.*.md read
6
+ * the same thing (see command-docs.ts).
7
+ */
8
+ export declare const DOCS_URL = "https://docs.vibeapi.cn/zh/docs/coding-tools/commands";
9
+ export interface HelpExample {
10
+ /** The command line, e.g. `vibecli base auto`. */
11
+ command: string;
12
+ /** What it does, already translated. */
13
+ note: string;
14
+ }
15
+ export interface HelpSection {
16
+ title: string;
17
+ /** [term, description] pairs. */
18
+ rows: Array<[string, string]>;
19
+ }
20
+ /**
21
+ * Per-command "affordance" (same idea as the eyre CLI's affordance files): when to
22
+ * reach for the command, what must be true first, and which command to use instead
23
+ * in which case — so a person or an agent reading `--help` knows the next step.
24
+ */
25
+ export interface CommandHelpData {
26
+ /** 何时用 / When to use. */
27
+ when: string;
28
+ /** 前提 / Prerequisites, one per line. */
29
+ prerequisites: string[];
30
+ /** 替代 / Alternatives: another command and when to use it instead. */
31
+ alternatives: HelpExample[];
32
+ sections: HelpSection[];
33
+ examples: HelpExample[];
34
+ }
35
+ /** Attaches extra sections and examples to a command and prints them after its help. */
36
+ export declare function attachCommandHelp(cmd: Command, data: Partial<CommandHelpData>): Command;
37
+ export declare function getCommandHelp(cmd: Command): CommandHelpData;
38
+ /** `vibecli config`, `vibecli codex sessions`, ... */
39
+ export declare function commandPath(cmd: Command): string;
40
+ /** Visible subcommands (the implicit `help` command excluded). */
41
+ export declare function visibleSubcommands(cmd: Command): Command[];
42
+ /** The lines pointing to more help for this command. */
43
+ export declare function learnMoreRows(cmd: Command): Array<[string, string]>;
44
+ export declare function renderHelpExtras(cmd: Command): string;
45
+ /** Commander's built-in headings, translated; group headings we set are already translated. */
46
+ export declare function localizeTitle(title: string): string;
47
+ /** Option text with its default, translated (only options that take a value show one). */
48
+ export declare function describeOption(option: Option): string;
49
+ export declare function describeArgument(argument: Argument): string;
50
+ /** Shared by every command (commander copies it into subcommands created afterwards). */
51
+ export declare function helpConfiguration(): HelpConfiguration;
52
+ /**
53
+ * The first word that names a command (skips global options and the value of `--base`).
54
+ */
55
+ export declare function firstCommandWord(args: readonly string[]): string | undefined;
56
+ /** `-h` / `--help` anywhere, or `vibecli help ...`: only print help, change nothing. */
57
+ export declare function isHelpRequest(args: readonly string[]): boolean;
@@ -0,0 +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 r(e){let t=e;for(;t.parent;)t=t.parent;return t}export function visibleSubcommands(e){return e.commands.filter(e=>!e._hidden)}const o=34;function i(e){const n=e.filter(([,e])=>e),r=Math.min(o,Math.max(0,...n.map(([e])=>t(e)))),i=[];for(const[n,o]of e){const e=t(n);o?e>r?i.push(` ${n}`,` ${" ".repeat(r)} ${o}`):i.push(` ${n}${" ".repeat(r-e)} ${o}`):i.push(` ${n}`)}return i}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(r(t))} --help`,e.t("help.learn_more.all_commands")]),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,...i(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"),...i(n.alternatives.map(e=>[e.command,e.note]))),n.examples.length>0&&r.push("",e.t("help.title.examples"),...i(n.examples.map(e=>[e.command,e.note]))),r.push("",e.t("help.title.learn_more"),...i(learnMoreRows(t))),r.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,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?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)}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Renders the command reference (docs/commands.<locale>.md) from the same command
3
+ * tree and help data `--help` prints, so the two cannot drift. Run `pnpm gen:docs`
4
+ * after changing commands, options, examples or their texts; a test fails while the
5
+ * committed files are stale.
6
+ */
7
+ export declare const DOC_LOCALES: readonly ["zh_CN", "en_US"];
8
+ export type DocLocale = (typeof DOC_LOCALES)[number];
9
+ export declare function commandDocsPath(locale: DocLocale): string;
10
+ /** The Markdown for one locale; the current locale is restored afterwards. */
11
+ export declare function generateCommandDocs(locale: DocLocale): string;
@@ -0,0 +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 u(t){return n(t).replace(/\s+/g,"-").toLowerCase()}function m(t){return`[${c(n(t))}](#${u(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 $(t){return t.split("\n").filter(Boolean).flatMap(t=>[t,""])}function g(t){return r(t).flatMap(t=>[t,...g(t)])}function x(e,s){const i=e.createHelp(),g=p(e),x=[`<a id="${u(e)}"></a>`,"",`## ${c(n(e))}`,""];x.push(...$(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=>[m(t),t.summary()||t.description()])),""));for(const t of g.sections)x.push(`**${l(t.title)}**`,""),x.push(...h([a("item"),a("description")],t.rows.map(([t,e])=>[c(t),e])),"");g.when&&x.push(`**${l(t.t("help.title.when"))}**`,"",...$(g.when)),g.prerequisites.length>0&&x.push(`**${l(t.t("help.title.prerequisites"))}**`,"",...g.prerequisites.map(t=>`- ${t}`),""),g.alternatives.length>0&&(x.push(`**${l(t.t("help.title.alternatives"))}**`,""),x.push(...h([a("command"),a("use_instead")],g.alternatives.map(t=>[c(t.command),t.note])),"")),g.examples.length>0&&(x.push(`**${l(t.t("help.title.examples"))}**`,"","```bash"),g.examples.forEach((t,e)=>{e>0&&x.push(""),x.push(`# ${t.note}`,t.command)}),x.push("```",""));const j=[c(`${n(e)} --help`)];return e.parent&&e.parent!==s&&j.push(m(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")}`,"",...$(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=>[m(t),t.summary()||t.description()])),"");const s=p(e).examples;s.length>0&&(n.push(`## ${l(t.t("help.title.examples"))}`,"","```bash"),s.forEach((t,e)=>{e>0&&n.push(""),n.push(`# ${t.note}`,t.command)}),n.push("```",""));for(const t of g(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,17 +1,21 @@
1
1
  import { Command as Commander } from 'commander';
2
+ export { buildProgram } from './program.js';
3
+ /** Runs the CLI: startup tasks (env cleanup, self-update, model menu refresh), then commander. */
2
4
  export declare class Command {
3
5
  private program;
4
6
  /** Set by `preflightArgs`: this run configures tools (see CONFIGURING_COMMANDS). */
5
7
  private configuring;
6
8
  constructor();
7
- private getVersion;
8
- private setupProgram;
9
- private handleInitCommand;
10
9
  /**
11
10
  * 配置类命令(CONFIGURING_COMMANDS 与向导)启动时检测 shell 环境里泄漏的
12
11
  * ANTHROPIC_BASE_URL / ANTHROPIC_API_KEY 并清除,否则它们会覆盖 vibecli 写进各工具配置文件的凭据。
13
12
  */
14
13
  private cleanupLeakedEnvVars;
14
+ /**
15
+ * Reads the global flags before commander runs. A help request (`-h` / `--help`
16
+ * anywhere, or `vibecli help ...`) only prints help: it neither applies `--base`
17
+ * nor counts as configuring, so it never touches the user's files.
18
+ */
15
19
  private preflightArgs;
16
20
  execute(args: string[]): Promise<void>;
17
21
  getProgram(): Commander;
@@ -1 +1 @@
1
- import{Command as e}from"commander";import{i18n as o,detectSystemLang as a}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 d}from"../commands/logs.js";import{completionCommand as p}from"../commands/completion.js";import{benchCommand as l}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{runModelRefresh as u}from"./model-refresh.js";import{upgradeCommand as f}from"../commands/upgrade.js";import{codexSessionsCommand as h}from"../commands/codex-sessions.js";import{setupCommand as y}from"../commands/setup.js";import{baseCommand as k}from"../commands/base.js";import{normalizeBaseUrl as b}from"./gateway-addresses.js";import w from"chalk";import{readFileSync as v}from"fs";import{join as $,dirname as x}from"path";import{fileURLToPath as C}from"url";import{setRuntimeOptions as j,detectColorPreferenceFromEnv as A,isColorEnabled as I,isJsonMode as P}from"./runtime-options.js";import{cleanupAnthropicEnvVars as D,machineEnvVarsLeft as R}from"./env-cleanup.js";import{runStartupUpdate as S}from"./auto-update.js";const _=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const i=t.isLangChosen()?t.getLang():a();o.loadFromConfig(i),this.program=new e,this.setupProgram()}getVersion(){try{const e=C(import.meta.url),o=x(e),a=$(o,"../../package.json");return JSON.parse(v(a,"utf-8")).version}catch{return"1.0.0"}}setupProgram(){this.program.name("vibecli").description(o.t("cli.title")).version(this.getVersion(),"-v, --version",o.t("commands.version")).helpOption("-h, --help",o.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(o.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("--grokkey <key>","Dedicated API key for Grok Build").option("--desktopkey <key>","Dedicated API key for Claude Desktop (3p mode)").option("--1m","Enable the 1M context window for Codex").option("--no-1m","Disable the 1M context window for Codex").option("--claude-official <on|off>","Claude Desktop: show (on) or hide (off, default) the official Claude.ai sign-in entry").option("--desktop-registry <on|off>","Windows Claude Desktop: always write the config to the registry policy (on, asks for admin once if needed) or decide automatically (off)").option("--force","Replace each tool's config files wholesale (snapshotted first) instead of merging — repairs hand-broken configs").option("--all","Configure every tool the key can serve (default behavior)").action(async e=>{await y({key:e.key,claudekey:e.claudekey,codexkey:e.codexkey,grokkey:e.grokkey,desktopkey:e.desktopkey,all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force})}),this.program.command("init").description(o.t("commands.init")).action(async()=>{await this.handleInitCommand()});const e=this.program.command("lang").description(o.t("commands.lang"));e.command("show").description(o.t("lang.show_usage")).action(async()=>{await n(["show"])}),e.command("set <locale>").description(o.t("lang.set_usage")).action(async e=>{await n(["set",e])});const a=this.program.command("auth").description(o.t("commands.auth"));a.argument("[token]","API token").action(async e=>{const o=[];e&&o.push(e),await s(o)}),a.command("revoke").description("Revoke saved API key").action(async()=>{await s(["revoke"])}),a.command("reload <tool>").description("Reload plan configuration to the specified tool (e.g., claude)").action(async e=>{await s(["reload",e])}),this.program.command("doctor").description(o.t("commands.doctor")).option("--deep","Also send one real Claude Code request through the written config").action(async e=>{await r({deep:e.deep})}),this.program.command("base [target]").description(o.t("commands.base")).action(async e=>{await k(e)}),this.program.command("status").description(o.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(e,o)=>{const a=[];e&&a.push(e),o&&a.push(o),await d(a)}),this.program.command("completion <shell>").description("Print shell completion script (bash|zsh|fish)").action(async e=>{await p([e])}),this.program.command("update").description("Check for a newer version across CNB and npm mirrors").action(async()=>{await g()}),this.program.command("upgrade [tools...]").description(o.t("commands.upgrade")).action(async(e=[])=>{await f(e)}),this.program.command("codex").description(o.t("commands.codex")).command("sessions").description(o.t("commands.codex_sessions")).option("--to <provider>","Provider to move the sessions under (default: the one Codex uses now)").option("--undo <dir>","Put the sessions back as recorded in this backup directory").action(async e=>{await h(e)}),this.program.command("bench").description("Benchmark the configured API endpoint").option("--samples <n>","number of samples to send","5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await l(o)}),this.program.command("config").description("Manage profiles, presets, backups, and per-tool config").argument("[args...]","Subcommand and arguments").allowUnknownOption(!0).action(async e=>{await c(e||[])}),this.program.command("enter [option]").description(o.t("commands.enter")).action(async e=>{if(e)switch(e){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 o=[e];await c(o);break}}else await i.run()}),this.program.action(async()=>{await i.run()}),this.program.configureHelp({sortSubcommands:!0,subcommandTerm:e=>e.name()+" "+e.usage()}),this.program.addHelpText("after",`\n${w.bold(o.t("cli.examples"))}:\n ${w.gray("$ vibecli # Interactive main menu")}\n ${w.gray("$ vibecli init # Run first-time setup wizard")}\n ${w.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${w.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c")}\n ${w.gray("$ vibecli setup --desktopkey sk-d --claude-official off # Claude Desktop, hide Claude.ai login")}\n ${w.gray("$ vibecli setup --key sk-xxx --force # Replace broken tool configs with the recommended ones")}\n ${w.gray("$ vibecli config codex --force # Same, for one tool")}\n ${w.gray("$ vibecli status --json # Machine-readable status")}\n ${w.gray("$ vibecli config profile list")}\n ${w.gray("$ vibecli config profile create work")}\n ${w.gray("$ vibecli config profile use work")}\n ${w.gray("$ vibecli config preset save fast")}\n ${w.gray("$ vibecli config backup create snapshot")}\n ${w.gray("$ vibecli auth <token> --non-interactive")}\n ${w.gray("$ vibecli auth revoke --yes")}\n ${w.gray("$ vibecli logs path")}\n ${w.gray("$ vibecli completion bash")}\n ${w.gray("$ vibecli bench --samples 3")}\n ${w.gray("$ vibecli update")}\n ${w.gray("$ vibecli upgrade claude-code")}\n ${w.gray("$ vibecli base # List gateway addresses and test each one")}\n ${w.gray("$ vibecli base auto # Switch every tool to the first address that works")}\n ${w.gray("$ vibecli setup --key sk-xxx --base https://www.vibeapi.si # Configure on another address")}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const e=D();if(0===e.length||P())return;const a=o.t("messages.env_vars_cleared",{vars:e.join(", ")});console.log(I()?w.yellow(a):a);const t=R();if(t.length>0){const e=o.t("messages.env_vars_machine_left",{vars:t.join(", ")});console.log(I()?w.yellow(e):e)}}preflightArgs(e){const o=o=>e.includes(o),a=!o("--no-color")&&A();let i,n;j({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:a}),a||(w.level=0);for(let o=0;o<e.length;o+=1){const a=e[o];"--base"===a&&e[o+1]?(i=e[o+1],o+=1):a.startsWith("--base=")?i=a.slice(7):n||a.startsWith("-")||(n=a)}const s=void 0===n&&!["--help","-h","--version","-v"].some(o);this.configuring=s||void 0!==n&&_.has(n),i&&t.setBaseUrl(b(i)??i,this.configuring)}async execute(e){try{if(this.preflightArgs(e),this.configuring&&this.cleanupLeakedEnvVars(),(await S(e)).handled)return;await u(e),await this.program.parseAsync(e,{from:"user"})}catch(e){if(e instanceof Error){const a=I()?w.red:e=>e;console.error(a(o.t("cli.error_general")),e.message)}process.exit(1)}}getProgram(){return this.program}}
1
+ import{i18n as r,detectSystemLang as o}from"./i18n.js";import{configManager as e}from"./config.js";import{runModelRefresh as s}from"./model-refresh.js";import{normalizeBaseUrl as t}from"./gateway-addresses.js";import n from"chalk";import{setRuntimeOptions as i,detectColorPreferenceFromEnv as a,isColorEnabled as c,isJsonMode as m}from"./runtime-options.js";import{cleanupAnthropicEnvVars as g,machineEnvVarsLeft as l}from"./env-cleanup.js";import{runStartupUpdate as f}from"./auto-update.js";import{buildProgram as p}from"./program.js";import{firstCommandWord as h,isHelpRequest as u}from"./cli-help.js";export{buildProgram}from"./program.js";const d=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const s=e.isLangChosen()?e.getLang():o();r.loadFromConfig(s),this.program=p()}cleanupLeakedEnvVars(){const o=g();if(0===o.length||m())return;const e=r.t("messages.env_vars_cleared",{vars:o.join(", ")});console.log(c()?n.yellow(e):e);const s=l();if(s.length>0){const o=r.t("messages.env_vars_machine_left",{vars:s.join(", ")});console.log(c()?n.yellow(o):o)}}preflightArgs(r){const o=o=>r.includes(o),s=!o("--no-color")&&a();if(i({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:s}),s||(n.level=0),this.configuring=!1,u(r))return;let c;for(let o=0;o<r.length;o+=1){const e=r[o];"--base"===e&&r[o+1]?(c=r[o+1],o+=1):e.startsWith("--base=")&&(c=e.slice(7))}const m=h(r),g=void 0===m&&!["--version","-v"].some(o);this.configuring=g||void 0!==m&&d.has(m),c&&e.setBaseUrl(t(c)??c,this.configuring)}async execute(o){try{if(this.preflightArgs(o),!u(o)){if(this.configuring&&this.cleanupLeakedEnvVars(),(await f(o)).handled)return;await s(o)}await this.program.parseAsync(o,{from:"user"})}catch(o){if(o instanceof Error){const e=c()?n.red:r=>r;console.error(e(r.t("cli.error_general")),o.message)}process.exit(1)}}getProgram(){return this.program}}
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as o,readFileSync as t,writeFileSync as r}from"fs";import{dirname as n,join as s}from"path";import i from"chalk";import{configManager as l}from"./config.js";import{i18n as f}from"./i18n.js";import{resolveModelCatalog as d}from"./model-catalog.js";import{listAdapters as c}from"./tools/registry.js";import{UserActionNeeded as a}from"./tools/types.js";import{logger as u}from"../utils/logger.js";import{resolveUpdateCachePath as m}from"./auto-update.js";export const MODEL_REFRESH_INTERVAL_MS=36e5;const h=new Set(["setup","init","config","auth","enter","completion","update","lang","logs"]),p=["--json","--dry-run","--help","-h","--version","-v"],g=[];export function shouldSkipModelRefresh(e,o=process.env){if("1"===o.VIBECLI_DISABLE_MODEL_REFRESH)return!0;if(p.some(o=>e.includes(o)))return!0;const t=e.find(e=>!e.startsWith("-"));return void 0!==t&&h.has(t)}export async function refreshModelMenus(){const e=new Map,o=[];g.length=0;for(const t of c())if(t.refreshModelMenu&&t.listedModels)try{const r=l.getApiKeyForTool(t.name);if(!r||t.detectCurrentConfig().apiKey!==r)continue;const n=t.listedModels();if(null===n)continue;e.has(r)||e.set(r,await d(r));const s=e.get(r);if(!s)continue;t.refreshModelMenu({apiKey:r,baseUrl:l.getBaseUrl(),models:l.getModelsForTool(t.name),settings:l.getToolSettings(t.name),catalog:s});const i=t.listedModels()??[],f=i.filter(e=>!n.includes(e)),c=n.filter(e=>!i.includes(e));(f.length>0||c.length>0)&&o.push({tool:t.displayName,added:f,removed:c})}catch(e){u.logError(`modelRefresh(${t.name})`,e),e instanceof a&&g.push(e.message)}return o}export async function runModelRefresh(l,d={}){const c=d.env??process.env;if(shouldSkipModelRefresh(l,c))return[];const a=d.now??Date.now(),h=function(e){return s(n(m(e)),"model-refresh.json")}(c);if(a-function(e){try{const o=JSON.parse(t(e,"utf-8")).refreshed_at;return"number"==typeof o?o:0}catch{return 0}}(h)<36e5)return[];let p=[];try{p=await refreshModelMenus(),e(n(h))||o(n(h),{recursive:!0}),r(h,JSON.stringify({refreshed_at:a})+"\n")}catch(e){u.logError("runModelRefresh",e)}const M=d.output??(e=>console.log(i.gray(e)));for(const e of g)M(e);for(const e of p){const o=[e.added.length>0?f.t("model_refresh.added",{models:e.added.join(", ")}):"",e.removed.length>0?f.t("model_refresh.removed",{models:e.removed.join(", ")}):""].filter(Boolean);M(f.t("model_refresh.changed",{tool:e.tool,changes:o.join(";")}))}return p}
1
+ import{existsSync as e,mkdirSync as o,readFileSync as t,writeFileSync as r}from"fs";import{dirname as n,join as s}from"path";import i from"chalk";import{configManager as l}from"./config.js";import{i18n as f}from"./i18n.js";import{resolveModelCatalog as d}from"./model-catalog.js";import{listAdapters as c}from"./tools/registry.js";import{UserActionNeeded as a}from"./tools/types.js";import{logger as u}from"../utils/logger.js";import{resolveUpdateCachePath as m}from"./auto-update.js";import{isHelpRequest as h}from"./cli-help.js";export const MODEL_REFRESH_INTERVAL_MS=36e5;const p=new Set(["setup","init","config","auth","enter","completion","update","lang","logs"]),g=["--json","--dry-run","--help","-h","--version","-v"],M=[];export function shouldSkipModelRefresh(e,o=process.env){if("1"===o.VIBECLI_DISABLE_MODEL_REFRESH)return!0;if(g.some(o=>e.includes(o))||h(e))return!0;const t=e.find(e=>!e.startsWith("-"));return void 0!==t&&p.has(t)}export async function refreshModelMenus(){const e=new Map,o=[];M.length=0;for(const t of c())if(t.refreshModelMenu&&t.listedModels)try{const r=l.getApiKeyForTool(t.name);if(!r||t.detectCurrentConfig().apiKey!==r)continue;const n=t.listedModels();if(null===n)continue;e.has(r)||e.set(r,await d(r));const s=e.get(r);if(!s)continue;t.refreshModelMenu({apiKey:r,baseUrl:l.getBaseUrl(),models:l.getModelsForTool(t.name),settings:l.getToolSettings(t.name),catalog:s});const i=t.listedModels()??[],f=i.filter(e=>!n.includes(e)),c=n.filter(e=>!i.includes(e));(f.length>0||c.length>0)&&o.push({tool:t.displayName,added:f,removed:c})}catch(e){u.logError(`modelRefresh(${t.name})`,e),e instanceof a&&M.push(e.message)}return o}export async function runModelRefresh(l,d={}){const c=d.env??process.env;if(shouldSkipModelRefresh(l,c))return[];const a=d.now??Date.now(),h=function(e){return s(n(m(e)),"model-refresh.json")}(c);if(a-function(e){try{const o=JSON.parse(t(e,"utf-8")).refreshed_at;return"number"==typeof o?o:0}catch{return 0}}(h)<36e5)return[];let p=[];try{p=await refreshModelMenus(),e(n(h))||o(n(h),{recursive:!0}),r(h,JSON.stringify({refreshed_at:a})+"\n")}catch(e){u.logError("runModelRefresh",e)}const g=d.output??(e=>console.log(i.gray(e)));for(const e of M)g(e);for(const e of p){const o=[e.added.length>0?f.t("model_refresh.added",{models:e.added.join(", ")}):"",e.removed.length>0?f.t("model_refresh.removed",{models:e.removed.join(", ")}):""].filter(Boolean);g(f.t("model_refresh.changed",{tool:e.tool,changes:o.join(";")}))}return p}
@@ -0,0 +1,2 @@
1
+ import { Command as Commander } from 'commander';
2
+ export declare function buildProgram(): Commander;
@@ -0,0 +1 @@
1
+ import{Command as e}from"commander";import{readFileSync as o}from"fs";import{join as t,dirname as i}from"path";import{fileURLToPath as s}from"url";import{i18n as a}from"./i18n.js";import{wizard as n}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as r,helpConfiguration as p}from"./cli-help.js";import{langCommand as m,authCommand as u,doctorCommand as d,configCommand as b,statusCommand as g}from"../commands/index.js";import{logsCommand as f}from"../commands/logs.js";import{completionCommand as x}from"../commands/completion.js";import{benchCommand as v}from"../commands/bench.js";import{updateCommand as y}from"../commands/update.js";import{upgradeCommand as k}from"../commands/upgrade.js";import{codexSessionsCommand as h}from"../commands/codex-sessions.js";import{setupCommand as _}from"../commands/setup.js";import{baseCommand as w}from"../commands/base.js";function j(e,o){return a.t(`help.${e}`,o)}function G(e,o){return{command:e,note:j(o)}}function O(e){const o=j(e);return o===`help.${e}`?"":o}function z(e,o=[]){return{when:O(`${e}.when`),prerequisites:O(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>G(e,o))}}function C(e){return e.helpCommand("help [command]",j("help_command"))}export function buildProgram(){const a=new e;a.name("vibecli").summary(j("root.summary")).description(j("root.description")).configureHelp(p()).allowExcessArguments(!0).optionsGroup(j("group.global_options")).helpOption("-h, --help",j("global.help")).version(function(){try{const e=i(s(import.meta.url));return JSON.parse(o(t(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",j("global.version")).option("--base <url>",j("global.base")).option("--non-interactive",j("global.non_interactive")).option("--json",j("global.json")).option("-y, --yes",j("global.yes")).option("--dry-run",j("global.dry_run")).option("--no-color",j("global.no_color")),a.commandsGroup(j("group.configure"));const O=a.command("setup").summary(j("setup.summary")).description(j("setup.description")).option("--key <key>",j("setup.opt.key")).option("--claudekey <key>",j("setup.opt.claudekey")).option("--codexkey <key>",j("setup.opt.codexkey")).option("--grokkey <key>",j("setup.opt.grokkey")).option("--desktopkey <key>",j("setup.opt.desktopkey")).option("--1m",j("setup.opt.one_m")).option("--no-1m",j("setup.opt.no_one_m")).option("--claude-official <on|off>",j("setup.opt.claude_official")).option("--desktop-registry <on|off>",j("setup.opt.desktop_registry")).option("--force",j("setup.opt.force")).option("--all",j("setup.opt.all")).action(async e=>{await _({key:e.key,claudekey:e.claudekey,codexkey:e.codexkey,grokkey:e.grokkey,desktopkey:e.desktopkey,all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force})});r(O,{...z("setup",[["vibecli init","setup.alt.init"],["vibecli config <tool>","setup.alt.config"],["vibecli auth <key>","setup.alt.auth"]]),sections:[{title:j("setup.autodetect_title"),rows:[["Claude",j("setup.autodetect.claude")],["GPT",j("setup.autodetect.gpt")],["Grok",j("setup.autodetect.grok")],["Gemini",j("setup.autodetect.gemini")]]}],examples:[G("vibecli setup --key sk-xxx","setup.ex.key"),G("vibecli setup --claudekey sk-a --codexkey sk-b","setup.ex.split"),G("vibecli setup --desktopkey sk-d --claude-official off","setup.ex.desktop"),G("vibecli setup --key sk-xxx --force","setup.ex.force"),G("vibecli setup --key sk-xxx --base https://www.vibeapi.si","setup.ex.base")]});const $=a.command("init").summary(j("init.summary")).description(j("init.description")).action(async()=>{await n.runFirstTimeSetup()});r($,{...z("init",[["vibecli setup --key <key>","init.alt.setup"],["vibecli","init.alt.menu"]]),examples:[G("vibecli init","init.ex.run"),G("vibecli init --base https://www.vibeapi.si","init.ex.base"),G("vibecli","init.ex.menu")]});const N=a.command("auth").summary(j("auth.summary")).description(j("auth.description")).argument("[token]",j("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await u(o)});C(N);const S=N.command("revoke").description(j("auth.revoke")).action(async()=>{await u(["revoke"])});r(S,{examples:[G("vibecli auth revoke","auth.ex.revoke_ask"),G("vibecli auth revoke --yes","auth.ex.revoke")]});const A=N.command("reload <tool>").description(j("auth.reload")).action(async e=>{await u(["reload",e])});r(A,{examples:[G("vibecli auth reload claude-code","auth.ex.reload"),G("vibecli auth reload claude-code --json","auth.ex.reload_json")]}),r(N,{...z("auth",[["vibecli setup --key <key>","auth.alt.setup"]]),examples:[G("vibecli auth","auth.ex.prompt"),G("vibecli auth sk-xxx --non-interactive","auth.ex.save"),G("vibecli auth revoke --yes","auth.ex.revoke"),G("vibecli auth reload claude-code","auth.ex.reload")]});const M=a.command("config").summary(j("config.summary")).description(j("config.description")).argument("[args...]",j("config.arg.args")).option("-f, --force",j("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await b(o.force?[...e,"--force"]:e)});r(M,{...z("config",[["vibecli setup --key <key> --force","config.alt.setup"],["vibecli status","config.alt.status"]]),sections:[{title:j("config.subcommands_title"),rows:[["<tool>",j("config.sub.tool")],["<tool> --force",j("config.sub.tool_force")],["<tool> --non-interactive",j("config.sub.tool_non_interactive")],["<tool> restore",j("config.sub.tool_restore")],["<tool> backups",j("config.sub.tool_backups")],["<tool> clear-model",j("config.sub.tool_clear_model")],["tool-model list",j("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",j("config.sub.tool_model_set")],["tool-model clear <tool>",j("config.sub.tool_model_clear")],["profile list",j("config.sub.profile_list")],["profile create <name>",j("config.sub.profile_create")],["profile use <name>",j("config.sub.profile_use")],["profile delete <name>",j("config.sub.profile_delete")],["preset list",j("config.sub.preset_list")],["preset save <name>",j("config.sub.preset_save")],["preset use <name>",j("config.sub.preset_use")],["preset delete <name>",j("config.sub.preset_delete")],["backup list",j("config.sub.backup_list")],["backup create [label]",j("config.sub.backup_create")],["backup restore <name>",j("config.sub.backup_restore")]]},{title:j("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[G("vibecli config codex","config.ex.menu"),G("vibecli config claude-code --force","config.ex.force"),G("vibecli config tool-model set codex gpt-6-astra","config.ex.tool_model"),G("vibecli config profile create work","config.ex.profile"),G("vibecli config backup create before-upgrade","config.ex.backup")]});const P=a.command("base").summary(j("base.summary")).description(j("base.description")).argument("[target]",j("base.arg.target")).action(async e=>{await w(e)});r(P,{...z("base",[["vibecli doctor","base.alt.doctor"],["vibecli bench","base.alt.bench"]]),sections:[{title:j("base.targets_title"),rows:[[j("base.target.none_term"),j("base.target.none")],[j("base.target.index_term"),j("base.target.index")],[j("base.target.url_term"),j("base.target.url")],["auto",j("base.target.auto")],["default",j("base.target.default",{url:l})]]}],examples:[G("vibecli base","base.ex.list"),G("vibecli base auto","base.ex.auto"),G("vibecli base 2","base.ex.index"),G("vibecli base https://www.vibeapi.si","base.ex.url"),G("vibecli base default","base.ex.default")]}),a.commandsGroup(j("group.diagnose"));const R=a.command("status").summary(j("status.summary")).description(j("status.description")).action(async()=>{await g()});r(R,{...z("status",[["vibecli doctor","status.alt.doctor"]]),examples:[G("vibecli status","status.ex.show"),G("vibecli status --json","status.ex.json")]});const T=a.command("doctor").summary(j("doctor.summary")).description(j("doctor.description")).option("--deep",j("doctor.opt.deep")).action(async e=>{await d({deep:e.deep})});r(T,{...z("doctor",[["vibecli base auto","doctor.alt.base"],["vibecli logs tail","doctor.alt.logs"]]),examples:[G("vibecli doctor","doctor.ex.run"),G("vibecli doctor --deep","doctor.ex.deep")]});const U=a.command("bench").summary(j("bench.summary")).description(j("bench.description")).option("--samples <n>",j("bench.opt.samples"),"5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await v(o)});r(U,{...z("bench",[["vibecli base","bench.alt.base"]]),examples:[G("vibecli bench","bench.ex.run"),G("vibecli bench --samples 3","bench.ex.samples"),G("vibecli bench --json","bench.ex.json")]});const q=a.command("logs").summary(j("logs.summary")).description(j("logs.description")).argument("[action]",j("logs.arg.action")).argument("[file]",j("logs.arg.file")).action(async(e,o)=>{const t=[];e&&t.push(e),o&&t.push(o),await f(t)});r(q,{...z("logs",[["vibecli doctor","logs.alt.doctor"]]),sections:[{title:j("logs.actions_title"),rows:[["list",j("logs.action.list")],["tail [file]",j("logs.action.tail")],["path",j("logs.action.path")]]}],examples:[G("vibecli logs","logs.ex.list"),G("vibecli logs tail","logs.ex.tail"),G("vibecli logs path","logs.ex.path")]}),a.commandsGroup(j("group.maintain"));const B=a.command("upgrade").summary(j("upgrade.summary")).description(j("upgrade.description")).argument("[tools...]",j("upgrade.arg.tools")).action(async(e=[])=>{await k(e)});r(B,{...z("upgrade",[["vibecli update","upgrade.alt.update"]]),examples:[G("vibecli upgrade","upgrade.ex.all"),G("vibecli upgrade claude-code","upgrade.ex.one"),G("vibecli upgrade codex agy","upgrade.ex.many")]});const E=a.command("update").summary(j("update.summary")).description(j("update.description")).action(async()=>{await y()});r(E,{...z("update",[["vibecli upgrade","update.alt.upgrade"]]),examples:[G("vibecli update","update.ex.check"),G("vibecli update --json","update.ex.json")]});const F=a.command("codex").summary(j("codex.summary")).description(j("codex.description"));C(F);const H=F.command("sessions").summary(j("codex_sessions.summary")).description(j("codex_sessions.description")).option("--to <provider>",j("codex_sessions.opt.to")).option("--undo <dir>",j("codex_sessions.opt.undo")).action(async e=>{await h(e)});r(F,{...z("codex"),examples:[G("vibecli codex sessions","codex_sessions.ex.move"),G("vibecli codex sessions --undo <dir>","codex_sessions.ex.undo")]}),r(H,{...z("codex_sessions",[["vibecli codex sessions --undo <dir>","codex_sessions.alt.undo"]]),examples:[G("vibecli codex sessions","codex_sessions.ex.move"),G("vibecli codex sessions --to custom","codex_sessions.ex.to"),G("vibecli codex sessions --undo <dir>","codex_sessions.ex.undo")]});const J=a.command("lang").summary(j("lang.summary")).description(j("lang.description"));C(J);const K=J.command("show").description(j("lang.show")).action(async()=>{await m(["show"])}),L=J.command("set <locale>").description(j("lang.set")).action(async e=>{await m(["set",e])}),D=[G("vibecli lang show","lang.ex.show"),G("vibecli lang set en_US","lang.ex.set_en"),G("vibecli lang set zh_CN","lang.ex.set_zh")];r(J,{...z("lang",[["vibecli enter lang","lang.alt.enter"]]),examples:D}),r(K,{examples:[D[0],G("vibecli lang show --json","lang.ex.show_json")]}),r(L,{examples:D.slice(1)});const I=a.command("completion").summary(j("completion.summary")).description(j("completion.description")).argument("<shell>",j("completion.arg.shell")).action(async e=>{await x([e])});r(I,{...z("completion"),examples:[G("vibecli completion bash > ~/.vibecli-completion.bash","completion.ex.bash"),G("vibecli completion zsh > ~/.vibecli-completion.zsh","completion.ex.zsh"),G("vibecli completion fish > ~/.config/fish/completions/vibecli.fish","completion.ex.fish")]});const Q=a.command("enter").summary(j("enter.summary")).description(j("enter.description")).argument("[option]",j("enter.arg.option")).action(async e=>{if(e)switch(e){case"lang":case"language":await n.configLanguage();break;case"apikey":case"api-key":await n.configApiKey();break;case"models":await n.configModels();break;default:await b([e])}else await n.run()});r(Q,{...z("enter",[["vibecli","enter.alt.menu"],["vibecli config <tool>","enter.alt.config"]]),sections:[{title:j("enter.options_title"),rows:[[j("enter.option.none_term"),j("enter.option.none")],["lang",j("enter.option.lang")],["apikey",j("enter.option.apikey")],["models",j("enter.option.models")],["<tool>",j("enter.option.tool")]]}],examples:[G("vibecli enter","enter.ex.menu"),G("vibecli enter models","enter.ex.models"),G("vibecli enter codex","enter.ex.tool")]}),C(a),a.action(async()=>{await n.run()}),r(a,{examples:[G("vibecli","root.ex.menu"),G("vibecli setup --key sk-xxx","root.ex.setup"),G("vibecli doctor","root.ex.doctor"),G("vibecli base auto","root.ex.base"),G("vibecli config codex","root.ex.config")]});const V=e=>{for(const o of e.commands)o.helpOption("-h, --help",j("global.help")),V(o)};return V(a),a}
@@ -1 +1 @@
1
- import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{postApplyPrompts as d}from"./post-apply.js";import{i18n as p,detectSystemLang as m}from"./i18n.js";import{createBorderLine as u,createContentLine as g}from"../utils/string-width.js";import{validateApiKey as _,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as f}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as y}from"./tools/claude-desktop.js";import{addressesWithCurrent as h,ensureReachableGatewayAddress as z,fastestIndex as v,probeAll as k,probeSummary as x,reasonText as b,savedApiKey as C,switchGatewayAddress as S}from"../commands/base.js";import{readFileSync as M}from"fs";import{dirname as T,join as A}from"path";import{fileURLToPath as K}from"url";const N=T(K(import.meta.url)),B=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(B.bold("\n"+u("╔","╗","═",this.BOX_WIDTH))),console.log(B.bold(g(e,"║","║",this.BOX_WIDTH,"center"))),console.log(B.bold(u("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(p.t("wizard.hint_navigate")),t.gray(p.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=65,t=p.t("wizard.banner_subtitle"),a=g(t,"║","║",e,"center"),o=g("","║","║",e,"center"),i=g(`API Helper v${function(){try{return JSON.parse(M(A(N,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>g(t,"║","║",e,"center")),r=[u("╔","╗","═",e),o,...n,o,i,a,u("╚","╝","═",e)];console.log(B.bold("\n"+r.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{try{return Boolean(l.detectCurrentConfig(e.name).apiKey)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=p.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+p.t("wizard.goodbye_claude_hint"))}else a=p.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a))}async runFirstTimeSetup(){const e="zh_CN"===m();e&&(o.setLang("zh_CN"),p.setLocale("zh_CN")),this.resetScreen(),console.log(B.bold("\n"+p.t("wizard.welcome"))),console.log(t.gray(p.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(p.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await z(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_language"));const a=p.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+p.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void p.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(p.t(e.name)!==e.name?p.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+p.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+p.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:p.t("wizard.custom_model_mode"),choices:[{name:p.t("wizard.custom_model_single"),value:"single"},{name:p.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:p.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:p.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:p.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:p.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:p.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+p.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(p.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+p.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:p.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:p.t("wizard.load_config_now"),choices:[{name:p.t("wizard.load_config_yes"),value:!0},{name:p.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=h(),r=a(p.t("wizard.base_testing")).start(),s=await k(n,{apiKey:C(),samples:3});r.stop();const l=v(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${p.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${x(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:p.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const m=s[n.findIndex(e=>e.url===d)];m.ok?await S(d):console.log(t.red(p.t("base.unreachable",{url:d,reason:b(m)}))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+p.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+p.t("wizard.api_key_get_hint",{url:"https://www.vibeapi.cn/console/token"}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:p.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(p.t("wizard.validating_api_key")).start(),r=await _(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+p.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+p.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+p.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_tool"));const a=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:o}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+p.t("wizard.select_tool"),choices:[...a,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===o)this.printGoodbye(),process.exit(0);else if("back"===o)return;await this.configureTool(o,t)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+p.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:p.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(p.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+p.t("wizard.menu_title"));const o=[{name:"📥 "+p.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+p.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+p.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"}),o.push({name:"🧨 "+p.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+p.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+p.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+p.t("wizard.api_key_required"))),console.log(t.yellow(p.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(p.t("wizard.validating_api_key")).start(),n=await _(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(p.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?p.t("wizard.api_key_invalid"):p.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+p.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]),!1;const d="claude-code"===i,m=s(i),u=d||!m?p.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+p.t("wizard.config_models"));const g=[{name:"✅ "+p.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+p.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+p.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}],{choice:_}=await this.promptWithHints([{type:"list",name:"choice",message:p.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===_.type)return!1;if("default"===_.type)o.setToolModel(i,null);else if("preset"===_.type)o.setToolModel(i,r(_.preset));else if("custom"===_.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===_.type){const n=a(p.t("wizard.fetching_models")).start(),r=await w(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:p.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+p.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,f),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:p.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,f,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,y),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:p.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,y,Boolean(a))}return console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+p.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]);const m=a(p.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),m.stop(),l.printApplied(i),await d([i]),n.force&&console.log(t.yellow(p.t("config.force_done",{tool:c[i]?.displayName||i})));const a=c[i]?.command;a&&console.log(t.green("\n"+p.t("wizard.run_tool_hint",{command:a})));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(p.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+p.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+p.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(p.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(p.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(o),n.succeed(p.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(p.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(p.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(p.t("wizard.restore_no_backup")):(r.succeed(p.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(p.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(B("── "+p.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+p.t("wizard.settings")+" ──")),{name:"🔑 "+p.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+p.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+p.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+p.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
1
+ import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{postApplyPrompts as d}from"./post-apply.js";import{i18n as p,detectSystemLang as m}from"./i18n.js";import{createBorderLine as u,createContentLine as g}from"../utils/string-width.js";import{validateApiKey as _,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as f}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as y}from"./tools/claude-desktop.js";import{addressesWithCurrent as h,ensureReachableGatewayAddress as z,fastestIndex as v,probeAll as k,probeSummary as x,reasonText as b,savedApiKey as C,switchGatewayAddress as S}from"../commands/base.js";import{readFileSync as M}from"fs";import{dirname as T,join as A}from"path";import{fileURLToPath as K}from"url";const N=T(K(import.meta.url)),B=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(B.bold("\n"+u("╔","╗","═",this.BOX_WIDTH))),console.log(B.bold(g(e,"║","║",this.BOX_WIDTH,"center"))),console.log(B.bold(u("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(p.t("wizard.hint_navigate")),t.gray(p.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=65,t=p.t("wizard.banner_subtitle"),a=g(t,"║","║",e,"center"),o=g("","║","║",e,"center"),i=g(`VibeCLI v${function(){try{return JSON.parse(M(A(N,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>g(t,"║","║",e,"center")),r=[u("╔","╗","═",e),o,...n,o,i,a,u("╚","╝","═",e)];console.log(B.bold("\n"+r.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{try{return Boolean(l.detectCurrentConfig(e.name).apiKey)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=p.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+p.t("wizard.goodbye_claude_hint"))}else a=p.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a))}async runFirstTimeSetup(){const e="zh_CN"===m();e&&(o.setLang("zh_CN"),p.setLocale("zh_CN")),this.resetScreen(),console.log(B.bold("\n"+p.t("wizard.welcome"))),console.log(t.gray(p.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(p.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await z(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_language"));const a=p.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+p.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void p.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(p.t(e.name)!==e.name?p.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+p.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+p.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:p.t("wizard.custom_model_mode"),choices:[{name:p.t("wizard.custom_model_single"),value:"single"},{name:p.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:p.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:p.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:p.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:p.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:p.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+p.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(p.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+p.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:p.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:p.t("wizard.load_config_now"),choices:[{name:p.t("wizard.load_config_yes"),value:!0},{name:p.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=h(),r=a(p.t("wizard.base_testing")).start(),s=await k(n,{apiKey:C(),samples:3});r.stop();const l=v(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${p.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${x(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:p.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const m=s[n.findIndex(e=>e.url===d)];m.ok?await S(d):console.log(t.red(p.t("base.unreachable",{url:d,reason:b(m)}))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+p.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+p.t("wizard.api_key_get_hint",{url:"https://www.vibeapi.cn/console/token"}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:p.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(p.t("wizard.validating_api_key")).start(),r=await _(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+p.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+p.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+p.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_tool"));const a=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:o}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+p.t("wizard.select_tool"),choices:[...a,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===o)this.printGoodbye(),process.exit(0);else if("back"===o)return;await this.configureTool(o,t)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+p.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:p.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(p.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+p.t("wizard.menu_title"));const o=[{name:"📥 "+p.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+p.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+p.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"}),o.push({name:"🧨 "+p.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+p.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+p.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+p.t("wizard.api_key_required"))),console.log(t.yellow(p.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(p.t("wizard.validating_api_key")).start(),n=await _(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(p.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?p.t("wizard.api_key_invalid"):p.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+p.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]),!1;const d="claude-code"===i,m=s(i),u=d||!m?p.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+p.t("wizard.config_models"));const g=[{name:"✅ "+p.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+p.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+p.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}],{choice:_}=await this.promptWithHints([{type:"list",name:"choice",message:p.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===_.type)return!1;if("default"===_.type)o.setToolModel(i,null);else if("preset"===_.type)o.setToolModel(i,r(_.preset));else if("custom"===_.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===_.type){const n=a(p.t("wizard.fetching_models")).start(),r=await w(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:p.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+p.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,f),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:p.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,f,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,y),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:p.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,y,Boolean(a))}return console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+p.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]);const m=a(p.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),m.stop(),l.printApplied(i),await d([i]),n.force&&console.log(t.yellow(p.t("config.force_done",{tool:c[i]?.displayName||i})));const a=c[i]?.command;a&&console.log(t.green("\n"+p.t("wizard.run_tool_hint",{command:a})));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(p.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+p.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+p.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(p.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(p.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(o),n.succeed(p.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(p.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(p.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(p.t("wizard.restore_no_backup")):(r.succeed(p.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(p.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(B("── "+p.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+p.t("wizard.settings")+" ──")),{name:"🔑 "+p.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+p.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+p.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+p.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();