@vibeapi/cli 0.0.45 → 0.0.46

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
@@ -50,7 +50,7 @@ vibecli setup --1m
50
50
  vibecli setup --no-1m
51
51
  ```
52
52
 
53
- 配完直接运行 `claude` / `codex` / `grok` 即可。
53
+ 配完直接运行 `claude` / `codex` / `grok` 即可。Claude Desktop 默认隐藏官方(Claude.ai 账号)登录入口、只走网关,想保留就加 `--claude-official on`。
54
54
 
55
55
  ### 方式 B:交互式向导
56
56
 
@@ -81,6 +81,7 @@ vibecli config claude-code clear-model # 模型选择被钉住时,交还给
81
81
  - Claude Code 用默认模型时不写 `ANTHROPIC_*_MODEL` 环境变量,顶层 `model` 由 `settings-template.json` 提供(当前为 `opus[1m]`);显式选择其它模型时会覆盖该模板值。Codex 默认 `gpt-6-astra`,Grok Build 默认 `grok-4.6`,其余工具默认 `gpt-5.5`。
82
82
  - Codex 默认启用 1M 上下文窗口(自动压缩阈值 900K);交互配置 Codex 时可取消。
83
83
  - **不动你的其它配置**:只改本工具的 provider 字段,你的 hooks、MCP、插件、权限设置原样保留。
84
+ - **配置改坏了一键重置**:`vibecli config <tool> --force`(或 `setup … --force`)先快照再整份重写为推荐配置,坏掉的 JSON/TOML 也能救回;不加 `--force` 时只幂等合并、不碰坏文件。
84
85
  - **改前自动备份 + 一键还原**:覆盖配置前先快照(每文件留 10 份),`vibecli config <tool> restore` 随时回退;还原本身也可再撤销。
85
86
  - **多 Profile + 可迁移凭据**:work/personal 各自独立;API Key 存在权限为 `0600` 的 `~/.vibecli/config.yaml`,与 Claude/Codex 本身的明文凭据方式一致,换机不会被主机绑定加密阻断。
86
87
  - **CI 友好**:所有命令支持 `--json` / `--non-interactive` / `--yes` / `--dry-run` / `--no-color`。
@@ -1 +1 @@
1
- import o from"inquirer";import e from"chalk";import{wizard as t}from"../lib/wizard.js";import{toolManager as n,SUPPORTED_TOOLS as l}from"../lib/tool-manager.js";import{i18n as i}from"../lib/i18n.js";import{configManager as r,DEFAULT_PROFILE_NAME as s}from"../lib/config.js";import{confirmAction as a,applyOrDryRun as c}from"../lib/confirm.js";import{isNonInteractive as d,shouldAutoConfirm as g}from"../lib/runtime-options.js";const f=/^[a-zA-Z0-9._-]+$/;function m(o,e){const t=(o||"").trim();if(!t||!f.test(t))throw new Error(i.t(`config.${e}_invalid_name`,{name:t||"<empty>"}));return t}function u(o,t){console.log("\n"+e.bold(o)),0!==t.length?t.forEach(o=>console.log(" "+o)):console.log(e.gray(" ("+i.t("config.empty_list")+")"))}function p(o,t){if("backups"===t){const t=n.listToolBackups(o).flatMap(o=>{const t=o.file.replace(/^.*[/\\]/,"");return o.backups.length?o.backups.map(o=>`${e.cyan(t)} ${e.gray(o.name.split(".bak-")[1]||o.name)}`):[`${e.cyan(t)} ${e.gray("("+i.t("config.empty_list")+")")}`]});return void u(i.t("config.tool_backups_title",{tool:l[o].displayName}),t)}const r=n.restorePrivateConfig(o).filter(o=>o.result.restored);0!==r.length?(console.log(e.green(i.t("config.config_restored",{tool:l[o].displayName}))),r.forEach(o=>console.log(e.gray(` ${o.file} ← ${o.result.from}`)))):console.log(e.yellow(i.t("config.restore_no_backup",{tool:l[o].displayName})))}async function _(s,d,g){if(!l[s])return void console.log(e.red(i.t("config.unknown_tool",{tool:s})));const f=(d[0]||"").toLowerCase();if("backups"!==f&&"list-backups"!==f){if("restore"===f){if(!await a({message:i.t("config.confirm_restore",{tool:l[s].displayName}),defaultValue:!1}))return;return void p(s,"restore")}if("clear-model"===f||"clear-models"===f){const o=l[s].displayName;return n.supportsClearPinnedModels(s)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:s},apply:async()=>{const t=n.clearPinnedModels(s);0!==t.length?(console.log(e.green(i.t("config.clear_model_done",{tool:o}))),t.forEach(o=>console.log(e.gray(` - ${o}`))),console.log(e.gray(i.t("config.clear_model_restart_hint",{tool:o})))):console.log(e.yellow(i.t("config.clear_model_none",{tool:o})))}}):void console.log(e.yellow(i.t("config.clear_model_unsupported",{tool:o})))}if(!n.isToolInstalled(s)){if(g.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));const{shouldInstall:t}=await o.prompt([{type:"confirm",name:"shouldInstall",message:i.t("wizard.install_tool_confirm"),default:!0}]);if(!t)return void console.log(e.yellow(i.t("wizard.install_skipped")));try{await n.installTool(s)}catch(o){return console.error(e.red(i.t("install.install_failed_detail"))),void(o instanceof Error&&o.message&&console.error(e.gray(o.message)))}}if(g.nonInteractive){const o=r.getApiKeyForTool(s);return o?(await n.applyPrivateConfig(s,o,r.getModelsForTool(s)),console.log(e.green(i.t("config.tool_config_loaded",{tool:l[s].displayName}))),void n.applyNotes(s).forEach(o=>console.log(e.yellow(o)))):void console.log(e.red(i.t("wizard.api_key_required")))}await t.showToolMenu(s)}else p(s,"backups")}export async function configCommand(t){const{positional:n,options:p}=function(o){const e=[],t={};(d()||g())&&(t.nonInteractive=!0);for(const n of o)"--non-interactive"===n||"-y"===n?t.nonInteractive=!0:e.push(n);return{positional:e,options:t}}(t),y=n[0],v=n.slice(1);if(y){switch(y){case"profile":return void await async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.getActiveProfileName(),t=r.listProfiles().map(t=>{const n=t===o;return`${n?e.green("●"):e.gray("○")} ${t}${n?e.gray(" ("+i.t("config.profile_active_label")+")"):""}`});return void u(i.t("config.profile_list_title"),t)}if("create"===t){const o=m(n,"profile");return r.listProfiles().includes(o)?void console.log(e.yellow(i.t("config.profile_exists",{name:o}))):(r.createProfile(o),void console.log(e.green(i.t("config.profile_created",{name:o}))))}if("use"===t){const o=m(n,"profile");return r.setActiveProfile(o),void console.log(e.green(i.t("config.profile_activated",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"profile");return o===s&&1===r.listProfiles().length?void console.log(e.yellow(i.t("config.profile_cannot_delete_last"))):void await c({description:i.t("config.profile_delete_dry_run",{name:o}),json:{action:"profile_delete",name:o},apply:async()=>{await a({message:i.t("config.profile_delete_confirm",{name:o}),defaultValue:!1})?(r.deleteProfile(o),console.log(e.green(i.t("config.profile_deleted",{name:o})))):console.log(e.yellow(i.t("config.profile_delete_aborted")))}})}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"preset":return void function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=Object.entries(r.getCustomPresets()).map(([o,t])=>`${e.cyan(o)} ${e.gray(`H:${t.models.haiku} S:${t.models.sonnet} O:${t.models.opus}`)}`);return void u(i.t("config.preset_list_title"),o)}if("save"===t){const o=m(n,"preset");return r.saveCustomPreset(o,r.getModels()),void console.log(e.green(i.t("config.preset_saved",{name:o})))}if("use"===t||"apply"===t){const o=m(n,"preset"),t=r.getCustomPresets()[o];return t?(r.setModels(t.models),void console.log(e.green(i.t("config.preset_applied",{name:o})))):void console.log(e.red(i.t("config.preset_not_found",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"preset");return r.deleteCustomPreset(o),void console.log(e.green(i.t("config.preset_deleted",{name:o})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"tool-model":return void function(o){const t=o[0];if(!t||"list"===t){const o=r.getProfile().tool_models||{},t=Object.entries(o).map(([o,t])=>{const n=Object.entries(t).map(([o,e])=>`${o}=${e}`).join(" ");return`${e.cyan(o)} ${e.gray(n)}`});return void u(i.t("config.tool_model_list_title"),t)}if("set"===t){const t=(o[1]||"").trim(),n=o.length>=4?(o[2]||"").trim():"opus",s=(o.length>=4?o[3]:o[2]||"").trim();return l[t]?s&&f.test(n)?(r.setToolModel(t,{[n]:s}),void console.log(e.green(i.t("config.tool_model_set",{tool:t,slot:n,model:s})))):void console.log(e.red(i.t("config.tool_model_usage"))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}if("clear"===t||"remove"===t){const t=(o[1]||"").trim();return l[t]?(r.setToolModel(t,null),void console.log(e.green(i.t("config.tool_model_cleared",{tool:t})))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"backup":return void await function(o){return async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.listBackups().map(o=>{const t=new Date(o.mtimeMs).toISOString();return`${e.cyan(o.name)} ${e.gray(t)}`});return void u(i.t("config.backup_list_title"),o)}if("create"===t||"snapshot"===t){const o=r.createBackup(n);return void console.log(e.green(i.t("config.backup_created",{path:o})))}if("restore"===t)return n?void await c({description:i.t("config.backup_restore_dry_run",{name:n}),json:{action:"backup_restore",name:n},apply:async()=>{await a({message:i.t("config.backup_restore_confirm",{name:n}),defaultValue:!1})?(r.restoreBackup(n),console.log(e.green(i.t("config.backup_restored",{name:n})))):console.log(e.yellow(i.t("config.backup_restore_aborted")))}}):void console.log(e.red(i.t("config.backup_restore_missing_name")));console.log(e.red(i.t("config.unknown_action",{action:t})))}(o)}(v)}"claude-code"!==y&&"claude-code"!==v[0]?l[y]?await _(y,v,p):(console.error(e.red(i.t("config.unknown_command",{command:y}))),console.log(e.gray(i.t("config.usage_hint"))),Object.values(l).filter(o=>!o.hidden).forEach(o=>{console.log(e.gray(` - ${o.name}: ${o.displayName}`))})):await _("claude-code",v,p)}else await async function(t){if(t.nonInteractive)return void console.log(e.red(i.t("config.requires_argument")));const{selectedTool:n}=await o.prompt([{type:"list",name:"selectedTool",message:i.t("wizard.select_tool"),choices:Object.values(l).filter(o=>!o.hidden).map(o=>({name:`${o.displayName} (${o.name})`,value:o.name}))}]);await _(n,[],t)}(p)}
1
+ import o from"inquirer";import e from"chalk";import{wizard as t}from"../lib/wizard.js";import{toolManager as n,SUPPORTED_TOOLS as l}from"../lib/tool-manager.js";import{i18n as i}from"../lib/i18n.js";import{configManager as r,DEFAULT_PROFILE_NAME as s}from"../lib/config.js";import{confirmAction as a,applyOrDryRun as c}from"../lib/confirm.js";import{isNonInteractive as f,shouldAutoConfirm as d}from"../lib/runtime-options.js";const g=/^[a-zA-Z0-9._-]+$/;function m(o,e){const t=(o||"").trim();if(!t||!g.test(t))throw new Error(i.t(`config.${e}_invalid_name`,{name:t||"<empty>"}));return t}function u(o,t){console.log("\n"+e.bold(o)),0!==t.length?t.forEach(o=>console.log(" "+o)):console.log(e.gray(" ("+i.t("config.empty_list")+")"))}function p(o,t){if("backups"===t){const t=n.listToolBackups(o).flatMap(o=>{const t=o.file.replace(/^.*[/\\]/,"");return o.backups.length?o.backups.map(o=>`${e.cyan(t)} ${e.gray(o.name.split(".bak-")[1]||o.name)}`):[`${e.cyan(t)} ${e.gray("("+i.t("config.empty_list")+")")}`]});return void u(i.t("config.tool_backups_title",{tool:l[o].displayName}),t)}const r=n.restorePrivateConfig(o).filter(o=>o.result.restored);0!==r.length?(console.log(e.green(i.t("config.config_restored",{tool:l[o].displayName}))),r.forEach(o=>console.log(e.gray(` ${o.file} ← ${o.result.from}`)))):console.log(e.yellow(i.t("config.restore_no_backup",{tool:l[o].displayName})))}async function _(s,f,d){if(!l[s])return void console.log(e.red(i.t("config.unknown_tool",{tool:s})));const g=(f[0]||"").toLowerCase();if("backups"!==g&&"list-backups"!==g){if("restore"===g){if(!await a({message:i.t("config.confirm_restore",{tool:l[s].displayName}),defaultValue:!1}))return;return void p(s,"restore")}if("clear-model"===g||"clear-models"===g){const o=l[s].displayName;return n.supportsClearPinnedModels(s)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:s},apply:async()=>{const t=n.clearPinnedModels(s);0!==t.length?(console.log(e.green(i.t("config.clear_model_done",{tool:o}))),t.forEach(o=>console.log(e.gray(` - ${o}`))),console.log(e.gray(i.t("config.clear_model_restart_hint",{tool:o})))):console.log(e.yellow(i.t("config.clear_model_none",{tool:o})))}}):void console.log(e.yellow(i.t("config.clear_model_unsupported",{tool:o})))}if(!n.isToolInstalled(s)){if(d.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));const{shouldInstall:t}=await o.prompt([{type:"confirm",name:"shouldInstall",message:i.t("wizard.install_tool_confirm"),default:!0}]);if(!t)return void console.log(e.yellow(i.t("wizard.install_skipped")));try{await n.installTool(s)}catch(o){return console.error(e.red(i.t("install.install_failed_detail"))),void(o instanceof Error&&o.message&&console.error(e.gray(o.message)))}}if(d.nonInteractive||d.force){const o=r.getApiKeyForTool(s);if(!o)return void console.log(e.red(i.t("wizard.api_key_required")));if(d.force&&!d.nonInteractive&&!await a({message:i.t("config.confirm_force",{tool:l[s].displayName}),defaultValue:!1}))return;return await n.applyPrivateConfig(s,o,r.getModelsForTool(s),{force:d.force}),d.force&&console.log(e.yellow(i.t("config.force_done",{tool:l[s].displayName}))),console.log(e.green(i.t("config.tool_config_loaded",{tool:l[s].displayName}))),void n.applyNotes(s).forEach(o=>console.log(e.yellow(o)))}await t.showToolMenu(s)}else p(s,"backups")}export async function configCommand(t){const{positional:n,options:p}=function(o){const e=[],t={};(f()||d())&&(t.nonInteractive=!0);for(const n of o)"--non-interactive"===n||"-y"===n?t.nonInteractive=!0:"--force"===n||"-f"===n?t.force=!0:e.push(n);return{positional:e,options:t}}(t),y=n[0],v=n.slice(1);if(y){switch(y){case"profile":return void await async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.getActiveProfileName(),t=r.listProfiles().map(t=>{const n=t===o;return`${n?e.green("●"):e.gray("○")} ${t}${n?e.gray(" ("+i.t("config.profile_active_label")+")"):""}`});return void u(i.t("config.profile_list_title"),t)}if("create"===t){const o=m(n,"profile");return r.listProfiles().includes(o)?void console.log(e.yellow(i.t("config.profile_exists",{name:o}))):(r.createProfile(o),void console.log(e.green(i.t("config.profile_created",{name:o}))))}if("use"===t){const o=m(n,"profile");return r.setActiveProfile(o),void console.log(e.green(i.t("config.profile_activated",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"profile");return o===s&&1===r.listProfiles().length?void console.log(e.yellow(i.t("config.profile_cannot_delete_last"))):void await c({description:i.t("config.profile_delete_dry_run",{name:o}),json:{action:"profile_delete",name:o},apply:async()=>{await a({message:i.t("config.profile_delete_confirm",{name:o}),defaultValue:!1})?(r.deleteProfile(o),console.log(e.green(i.t("config.profile_deleted",{name:o})))):console.log(e.yellow(i.t("config.profile_delete_aborted")))}})}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"preset":return void function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=Object.entries(r.getCustomPresets()).map(([o,t])=>`${e.cyan(o)} ${e.gray(`H:${t.models.haiku} S:${t.models.sonnet} O:${t.models.opus}`)}`);return void u(i.t("config.preset_list_title"),o)}if("save"===t){const o=m(n,"preset");return r.saveCustomPreset(o,r.getModels()),void console.log(e.green(i.t("config.preset_saved",{name:o})))}if("use"===t||"apply"===t){const o=m(n,"preset"),t=r.getCustomPresets()[o];return t?(r.setModels(t.models),void console.log(e.green(i.t("config.preset_applied",{name:o})))):void console.log(e.red(i.t("config.preset_not_found",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"preset");return r.deleteCustomPreset(o),void console.log(e.green(i.t("config.preset_deleted",{name:o})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"tool-model":return void function(o){const t=o[0];if(!t||"list"===t){const o=r.getProfile().tool_models||{},t=Object.entries(o).map(([o,t])=>{const n=Object.entries(t).map(([o,e])=>`${o}=${e}`).join(" ");return`${e.cyan(o)} ${e.gray(n)}`});return void u(i.t("config.tool_model_list_title"),t)}if("set"===t){const t=(o[1]||"").trim(),n=o.length>=4?(o[2]||"").trim():"opus",s=(o.length>=4?o[3]:o[2]||"").trim();return l[t]?s&&g.test(n)?(r.setToolModel(t,{[n]:s}),void console.log(e.green(i.t("config.tool_model_set",{tool:t,slot:n,model:s})))):void console.log(e.red(i.t("config.tool_model_usage"))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}if("clear"===t||"remove"===t){const t=(o[1]||"").trim();return l[t]?(r.setToolModel(t,null),void console.log(e.green(i.t("config.tool_model_cleared",{tool:t})))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"backup":return void await function(o){return async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.listBackups().map(o=>{const t=new Date(o.mtimeMs).toISOString();return`${e.cyan(o.name)} ${e.gray(t)}`});return void u(i.t("config.backup_list_title"),o)}if("create"===t||"snapshot"===t){const o=r.createBackup(n);return void console.log(e.green(i.t("config.backup_created",{path:o})))}if("restore"===t)return n?void await c({description:i.t("config.backup_restore_dry_run",{name:n}),json:{action:"backup_restore",name:n},apply:async()=>{await a({message:i.t("config.backup_restore_confirm",{name:n}),defaultValue:!1})?(r.restoreBackup(n),console.log(e.green(i.t("config.backup_restored",{name:n})))):console.log(e.yellow(i.t("config.backup_restore_aborted")))}}):void console.log(e.red(i.t("config.backup_restore_missing_name")));console.log(e.red(i.t("config.unknown_action",{action:t})))}(o)}(v)}"claude-code"!==y&&"claude-code"!==v[0]?l[y]?await _(y,v,p):(console.error(e.red(i.t("config.unknown_command",{command:y}))),console.log(e.gray(i.t("config.usage_hint"))),Object.values(l).filter(o=>!o.hidden).forEach(o=>{console.log(e.gray(` - ${o.name}: ${o.displayName}`))})):await _("claude-code",v,p)}else await async function(t){if(t.nonInteractive)return void console.log(e.red(i.t("config.requires_argument")));const{selectedTool:n}=await o.prompt([{type:"list",name:"selectedTool",message:i.t("wizard.select_tool"),choices:Object.values(l).filter(o=>!o.hidden).map(o=>({name:`${o.displayName} (${o.name})`,value:o.name}))}]);await _(n,[],t)}(p)}
@@ -18,6 +18,14 @@
18
18
  * vibecli setup --no-1m
19
19
  * 复用当前 profile 已保存的 Codex Key,关闭 1M 上下文且不改写凭据。
20
20
  *
21
+ * vibecli setup ... --force
22
+ * 任何一种用法都可加:先快照、再整份删掉工具原有配置文件,用推荐配置重写——给把配置
23
+ * 改坏(乃至改成不合法 JSON/TOML)的用户兜底;不加时是幂等合并,遇到坏文件会拒绝。
24
+ *
25
+ * vibecli setup --claude-official on|off
26
+ * Claude Desktop 里是否保留官方(Claude.ai 账号)登录入口;默认 off(隐藏)。可与 --desktopkey /
27
+ * --key 同用,单独给则复用已保存的桌面端 Key 重新应用。
28
+ *
21
29
  * 重复执行即换令牌(幂等)。模型一律用默认组合,之后可在向导 / tool-model 里改。
22
30
  */
23
31
  export interface SetupCommandOptions {
@@ -28,5 +36,11 @@ export interface SetupCommandOptions {
28
36
  desktopkey?: string;
29
37
  all?: boolean;
30
38
  oneMillion?: boolean;
39
+ /** `on` = keep the Claude.ai sign-in entry visible in Claude Desktop; `off` = hide it. */
40
+ claudeOfficial?: string;
41
+ /** Replace each tool's config files wholesale (snapshotted first) instead of merging. */
42
+ force?: boolean;
31
43
  }
44
+ /** `--claude-official on|off` (also true/false, show/hide, 1/0, yes/no); undefined when unrecognized. */
45
+ export declare function parseOnOff(raw: string | undefined): boolean | undefined;
32
46
  export declare function setupCommand(options: SetupCommandOptions): Promise<void>;
@@ -1 +1 @@
1
- import e from"chalk";import{i18n as o}from"../lib/i18n.js";import{configManager as t}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as s}from"../lib/tool-manager.js";import{validateApiKey as l,fetchModels as i}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as n,setCodexOneMillionContext as d}from"../lib/tools/codex.js";async function p(e){const o=await i(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),probed:!0}}function r(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}function c(o){console.log(e.green(o))}function u(o){console.log(e.yellow(o))}function m(o){console.error(e.red(o))}async function y(t,a){console.log(e.gray(o.t("setup.validating",{label:t})));const s=await l(a);return!!s.valid||(m(o.t("setup.invalid_key",{label:t,reason:s.message||s.error||"invalid"})),!1)}async function k(l,i,d){const p=s[l];try{"codex"===l&&void 0!==d&&t.setToolSetting("codex",n,d),await a.applyPrivateConfig(l,i,t.getModelsForTool(l))}catch(e){return m(o.t("setup.apply_failed",{tool:p.displayName,reason:e instanceof Error?e.message:String(e)})),!1}return c(o.t("setup.configured",{tool:p.displayName,command:p.command})),"codex"===l&&void 0!==d&&c(o.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled")),a.applyNotes(l).forEach(e=>u(" "+e)),a.isToolInstalled(l)||console.log(e.gray(o.t("setup.install_hint",{tool:p.displayName,install:p.installCommand}))),!0}export async function setupCommand(e){const l=e.key?.trim(),i=e.claudekey?.trim(),g=e.codexkey?.trim(),f=e.grokkey?.trim(),b=e.desktopkey?.trim(),_=void 0!==e.oneMillion;if(!l&&!i&&!g&&!f&&!b&&_){if(!t.getApiKeyForTool("codex"))return m(o.t("setup.codex_1m_missing_key")),void(process.exitCode=1);try{const a=!0===e.oneMillion;t.setToolSetting("codex",n,a),d(a),c(o.t(a?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(e){m(o.t("setup.apply_failed",{tool:s.codex.displayName,reason:e instanceof Error?e.message:String(e)})),process.exitCode=1}return}if(!(l||i||g||f||b))return m(o.t("setup.usage")),void(process.exitCode=1);let h=0,x=0;const C=new Set,v=[];i&&v.push({tool:"claude-code",label:"--claudekey",apiKey:i,need:"claude"}),g&&v.push({tool:"codex",label:"--codexkey",apiKey:g,need:"gpt"}),f&&v.push({tool:"grok",label:"--grokkey",apiKey:f,need:"grok"}),b&&v.push({tool:"claude-desktop",label:"--desktopkey",apiKey:b,need:"claude"});for(const a of v){if(!await y(a.label,a.apiKey)){x+=1;continue}const l=await p(a.apiKey);!l.probed||r(l,a.need)?(l.probed||u(o.t("setup.probe_failed",{label:a.label})),t.setToolApiKey(a.tool,a.apiKey),await k(a.tool,a.apiKey,e.oneMillion)?(h+=1,C.add(a.tool)):x+=1):(m(o.t(`setup.key_no_${a.need}`,{label:a.label,tool:s[a.tool].displayName})),x+=1)}if(l){if(!await y("--key",l))return void(process.exitCode=1);t.setApiKey(l);const s=await p(l);if(s.probed||u(o.t("setup.probe_failed",{label:"--key"})),s.probed&&!s.hasClaude&&!s.hasGpt&&!s.hasGrok)return m(o.t("setup.key_no_family")),void(process.exitCode=1);const i=[{tool:"claude-code",capable:s.hasClaude,skipMsg:o.t("setup.skip_no_claude")},{tool:"codex",capable:s.hasGpt,skipMsg:o.t("setup.skip_no_gpt")},{tool:"grok",capable:s.hasGrok,skipMsg:o.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:s.hasClaude&&a.isToolInstalled("claude-desktop"),skipMsg:o.t("setup.skip_desktop_not_installed"),quiet:!s.hasClaude}];for(const o of i)C.has(o.tool)||(o.capable?await k(o.tool,l,e.oneMillion)?(h+=1,C.add(o.tool)):x+=1:o.quiet||u(o.skipMsg))}if(h>0){const e=[...C].map(e=>s[e]?.command).filter(Boolean).join(" / ");c("\n"+o.t("setup.done",{count:String(h),commands:e}))}(x>0||0===h)&&(process.exitCode=1)}
1
+ import e from"chalk";import{i18n as o}from"../lib/i18n.js";import{configManager as t}from"../lib/config.js";import{toolManager as s,SUPPORTED_TOOLS as a}from"../lib/tool-manager.js";import{validateApiKey as l,fetchModels as i}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as n}from"../lib/tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as r}from"../lib/tools/claude-desktop.js";async function p(e){const o=await i(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),probed:!0}}function c(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}export function parseOnOff(e){const o=(e??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(o)||!["off","false","hide","0","no","n"].includes(o)&&void 0}function u(o){console.log(e.green(o))}function f(o){console.log(e.yellow(o))}function m(o){console.error(e.red(o))}async function k(t,s){console.log(e.gray(o.t("setup.validating",{label:t})));const a=await l(s);return!!a.valid||(m(o.t("setup.invalid_key",{label:t,reason:a.message||a.error||"invalid"})),!1)}async function y(l,i,n,p,c){const k=a[l];try{"codex"===l&&void 0!==n&&t.setToolSetting("codex",d,n),"claude-desktop"===l&&void 0!==p&&t.setToolSetting("claude-desktop",r,!p),await s.applyPrivateConfig(l,i,t.getModelsForTool(l),{force:c})}catch(e){return m(o.t("setup.apply_failed",{tool:k.displayName,reason:e instanceof Error?e.message:String(e)})),!1}return c&&f(o.t("config.force_done",{tool:k.displayName})),u(o.t("setup.configured",{tool:k.displayName,command:k.command})),"codex"===l&&void 0!==n&&u(o.t(n?"setup.codex_1m_enabled":"setup.codex_1m_disabled")),s.applyNotes(l).forEach(e=>f(" "+e)),s.isToolInstalled(l)||console.log(e.gray(o.t("setup.install_hint",{tool:k.displayName,install:k.installCommand}))),!0}export async function setupCommand(e){const l=e.key?.trim(),i=e.claudekey?.trim(),r=e.codexkey?.trim(),g=e.grokkey?.trim(),_=e.desktopkey?.trim(),b=void 0!==e.oneMillion,h=void 0!==e.claudeOfficial;let x;if(h&&(x=parseOnOff(e.claudeOfficial),void 0===x))return m(o.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)})),void(process.exitCode=1);const C=Boolean(l||i||r||g||_);if(!C&&(b||h)){if(b)if(t.getApiKeyForTool("codex"))try{const s=!0===e.oneMillion;t.setToolSetting("codex",d,s),n(s),u(o.t(s?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(e){m(o.t("setup.apply_failed",{tool:a.codex.displayName,reason:e instanceof Error?e.message:String(e)})),process.exitCode=1}else m(o.t("setup.codex_1m_missing_key")),process.exitCode=1;if(h){const s=t.getApiKeyForTool("claude-desktop");s?await y("claude-desktop",s,void 0,x,e.force)||(process.exitCode=1):(m(o.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!C)return m(o.t("setup.usage")),void(process.exitCode=1);let v=0,w=0;const K=new Set,G=[];i&&G.push({tool:"claude-code",label:"--claudekey",apiKey:i,need:"claude"}),r&&G.push({tool:"codex",label:"--codexkey",apiKey:r,need:"gpt"}),g&&G.push({tool:"grok",label:"--grokkey",apiKey:g,need:"grok"}),_&&G.push({tool:"claude-desktop",label:"--desktopkey",apiKey:_,need:"claude"});for(const s of G){if(!await k(s.label,s.apiKey)){w+=1;continue}const l=await p(s.apiKey);!l.probed||c(l,s.need)?(l.probed||f(o.t("setup.probe_failed",{label:s.label})),t.setToolApiKey(s.tool,s.apiKey),await y(s.tool,s.apiKey,e.oneMillion,x,e.force)?(v+=1,K.add(s.tool)):w+=1):(m(o.t(`setup.key_no_${s.need}`,{label:s.label,tool:a[s.tool].displayName})),w+=1)}if(l){if(!await k("--key",l))return void(process.exitCode=1);t.setApiKey(l);const a=await p(l);if(a.probed||f(o.t("setup.probe_failed",{label:"--key"})),a.probed&&!a.hasClaude&&!a.hasGpt&&!a.hasGrok)return m(o.t("setup.key_no_family")),void(process.exitCode=1);const i=[{tool:"claude-code",capable:a.hasClaude,skipMsg:o.t("setup.skip_no_claude")},{tool:"codex",capable:a.hasGpt,skipMsg:o.t("setup.skip_no_gpt")},{tool:"grok",capable:a.hasGrok,skipMsg:o.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:a.hasClaude&&s.isToolInstalled("claude-desktop"),skipMsg:o.t("setup.skip_desktop_not_installed"),quiet:!a.hasClaude}];for(const o of i)K.has(o.tool)||(o.capable?await y(o.tool,l,e.oneMillion,x,e.force)?(v+=1,K.add(o.tool)):w+=1:o.quiet||f(o.skipMsg))}if(v>0){const e=[...K].map(e=>a[e]?.command).filter(Boolean).join(" / ");u("\n"+o.t("setup.done",{count:String(v),commands:e}))}(w>0||0===v)&&(process.exitCode=1)}
@@ -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 p}from"../commands/logs.js";import{completionCommand as l}from"../commands/completion.js";import{benchCommand as d}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{setupCommand as u}from"../commands/setup.js";import y from"chalk";import{readFileSync as h}from"fs";import{join as f,dirname as k}from"path";import{fileURLToPath as b}from"url";import{setRuntimeOptions as v,detectColorPreferenceFromEnv as w,isColorEnabled as $,isJsonMode as j}from"./runtime-options.js";import{cleanupAnthropicEnvVars as x}from"./env-cleanup.js";import{runStartupUpdate as C}from"./auto-update.js";export class Command{program;constructor(){const i=t.isFirstRun()?a():t.getLang();o.loadFromConfig(i),this.program=new e,this.setupProgram()}getVersion(){try{const e=b(import.meta.url),o=k(e),a=f(o,"../../package.json");return JSON.parse(h(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("--all","Configure every tool the key can serve (default behavior)").action(async e=>{await u({key:e.key,claudekey:e.claudekey,codexkey:e.codexkey,grokkey:e.grokkey,desktopkey:e.desktopkey,all:e.all,oneMillion:e["1m"]})}),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")).action(async()=>{await r()}),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 p(a)}),this.program.command("completion <shell>").description("Print shell completion script (bash|zsh|fish)").action(async e=>{await l([e])}),this.program.command("update").description("Check for a newer version across CNB and npm mirrors").action(async()=>{await g()}),this.program.command("bench").description("Benchmark the configured API endpoint").option("--samples <n>","number of samples to send","5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await d(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${y.bold(o.t("cli.examples"))}:\n ${y.gray("$ vibecli # Interactive main menu")}\n ${y.gray("$ vibecli init # Run first-time setup wizard")}\n ${y.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${y.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c")}\n ${y.gray("$ vibecli status --json # Machine-readable status")}\n ${y.gray("$ vibecli config profile list")}\n ${y.gray("$ vibecli config profile create work")}\n ${y.gray("$ vibecli config profile use work")}\n ${y.gray("$ vibecli config preset save fast")}\n ${y.gray("$ vibecli config backup create snapshot")}\n ${y.gray("$ vibecli auth <token> --non-interactive")}\n ${y.gray("$ vibecli auth revoke --yes")}\n ${y.gray("$ vibecli logs path")}\n ${y.gray("$ vibecli completion bash")}\n ${y.gray("$ vibecli bench --samples 3")}\n ${y.gray("$ vibecli update")}\n ${y.gray('$ vibecli --base "https://custom.api.com" init # Custom base URL')}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const e=x();if(0===e.length||j())return;const a=o.t("messages.env_vars_cleared",{vars:e.join(", ")});console.log($()?y.yellow(a):a)}preflightArgs(e){const o=o=>e.includes(o),a=!o("--no-color")&&w();let i;v({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:a}),a||(y.level=0);for(let o=0;o<e.length;o+=1){const a=e[o];if("--base"===a&&e[o+1]){i=e[o+1];break}if(a.startsWith("--base=")){i=a.slice(7);break}}i&&t.setBaseUrl(i)}async execute(e){try{if(this.preflightArgs(e),this.cleanupLeakedEnvVars(),(await C(e)).handled)return;await this.program.parseAsync(e,{from:"user"})}catch(e){if(e instanceof Error){const a=$()?y.red:e=>e;console.error(a(o.t("cli.error_general")),e.message)}process.exit(1)}}getProgram(){return this.program}}
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 l}from"../commands/logs.js";import{completionCommand as p}from"../commands/completion.js";import{benchCommand as d}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{setupCommand as u}from"../commands/setup.js";import f from"chalk";import{readFileSync as h}from"fs";import{join as y,dirname as k}from"path";import{fileURLToPath as b}from"url";import{setRuntimeOptions as v,detectColorPreferenceFromEnv as w,isColorEnabled as $,isJsonMode as x}from"./runtime-options.js";import{cleanupAnthropicEnvVars as C}from"./env-cleanup.js";import{runStartupUpdate as j}from"./auto-update.js";export class Command{program;constructor(){const i=t.isFirstRun()?a():t.getLang();o.loadFromConfig(i),this.program=new e,this.setupProgram()}getVersion(){try{const e=b(import.meta.url),o=k(e),a=y(o,"../../package.json");return JSON.parse(h(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("--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 u({key:e.key,claudekey:e.claudekey,codexkey:e.codexkey,grokkey:e.grokkey,desktopkey:e.desktopkey,all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,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")).action(async()=>{await r()}),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 l(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("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 d(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${f.bold(o.t("cli.examples"))}:\n ${f.gray("$ vibecli # Interactive main menu")}\n ${f.gray("$ vibecli init # Run first-time setup wizard")}\n ${f.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${f.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c")}\n ${f.gray("$ vibecli setup --desktopkey sk-d --claude-official off # Claude Desktop, hide Claude.ai login")}\n ${f.gray("$ vibecli setup --key sk-xxx --force # Replace broken tool configs with the recommended ones")}\n ${f.gray("$ vibecli config codex --force # Same, for one tool")}\n ${f.gray("$ vibecli status --json # Machine-readable status")}\n ${f.gray("$ vibecli config profile list")}\n ${f.gray("$ vibecli config profile create work")}\n ${f.gray("$ vibecli config profile use work")}\n ${f.gray("$ vibecli config preset save fast")}\n ${f.gray("$ vibecli config backup create snapshot")}\n ${f.gray("$ vibecli auth <token> --non-interactive")}\n ${f.gray("$ vibecli auth revoke --yes")}\n ${f.gray("$ vibecli logs path")}\n ${f.gray("$ vibecli completion bash")}\n ${f.gray("$ vibecli bench --samples 3")}\n ${f.gray("$ vibecli update")}\n ${f.gray('$ vibecli --base "https://custom.api.com" init # Custom base URL')}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const e=C();if(0===e.length||x())return;const a=o.t("messages.env_vars_cleared",{vars:e.join(", ")});console.log($()?f.yellow(a):a)}preflightArgs(e){const o=o=>e.includes(o),a=!o("--no-color")&&w();let i;v({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:a}),a||(f.level=0);for(let o=0;o<e.length;o+=1){const a=e[o];if("--base"===a&&e[o+1]){i=e[o+1];break}if(a.startsWith("--base=")){i=a.slice(7);break}}i&&t.setBaseUrl(i)}async execute(e){try{if(this.preflightArgs(e),this.cleanupLeakedEnvVars(),(await j(e)).handled)return;await this.program.parseAsync(e,{from:"user"})}catch(e){if(e instanceof Error){const a=$()?f.red:e=>e;console.error(a(o.t("cli.error_general")),e.message)}process.exit(1)}}getProgram(){return this.program}}
@@ -30,13 +30,26 @@ export declare class ToolManager {
30
30
  installTool(toolName: string): Promise<void>;
31
31
  getToolConfig(toolName: string): any;
32
32
  updateToolConfig(toolName: string, config: any): void;
33
- loadPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, catalog?: ModelCatalog): void;
33
+ /**
34
+ * `--force`: snapshot then delete every file the adapter would otherwise
35
+ * merge into, so the following apply starts from a clean slate. Meant for
36
+ * users who hand-edited a config into an unusable state — the merge path
37
+ * refuses to touch unparsable files, this path replaces them (backups keep
38
+ * the broken original recoverable via `restore`).
39
+ * @returns the files that were removed
40
+ */
41
+ forceResetConfig(toolName: string): string[];
42
+ loadPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, catalog?: ModelCatalog, options?: {
43
+ force?: boolean;
44
+ }): void;
34
45
  /**
35
46
  * `loadPrivateConfig` plus the network lookup adapters with
36
47
  * `wantsModelCatalog` need (what the key can reach, which models are 1M).
37
48
  * A failed lookup degrades to the profile's slots instead of failing the apply.
38
49
  */
39
- applyPrivateConfig(toolName: string, apiKey: string, models: VibecliModels): Promise<void>;
50
+ applyPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, options?: {
51
+ force?: boolean;
52
+ }): Promise<void>;
40
53
  /** Post-apply follow-ups the adapter wants shown to the user (may be empty). */
41
54
  applyNotes(toolName: string): string[];
42
55
  unloadPrivateConfig(toolName: string): void;
@@ -1 +1 @@
1
- import{execSync as o}from"child_process";import{i18n as n}from"./i18n.js";import t from"inquirer";import l from"chalk";import e from"terminal-link";import s from"ora";import{logger as i}from"../utils/logger.js";import{configManager as a}from"./config.js";import{getAdapter as r,listAdapters as c,TOOL_ADAPTERS as d}from"./tools/registry.js";import{listBackups as g,restoreBackup as m}from"./tools/backup.js";import{resolveModelCatalog as p}from"./model-catalog.js";function u(o){const n=d[o];return{name:n.name,command:n.command,installCommand:n.installCommand,configPath:n.configPath,displayName:n.displayName,...n.hidden?{hidden:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(d).map(o=>[o,u(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(n){const t=SUPPORTED_TOOLS[n];if(!t)return!1;const l=r(n);if(l?.isInstalled)try{return l.isInstalled()}catch{return!1}try{const n="win32"===process.platform?`where ${t.command}`:`which ${t.command}`;return o(n,{stdio:"pipe"}),!0}catch{return!1}}async installTool(a){const r=SUPPORTED_TOOLS[a];if(!r)throw new Error(`Unknown tool: ${a}`);const c=s(n.t("wizard.installing_tool")).start();try{c.info(l.gray("$ ")+l.white(r.installCommand)),c.stop(),o(r.installCommand,{stdio:"inherit"}),c.succeed(n.t("wizard.tool_installed"))}catch(s){c.fail(n.t("wizard.install_failed"));const d=(s.message||"")+(s.stderr?.toString()||"")+(s.stdout?.toString()||"");if(!(d.includes("EACCES")||d.includes("permission denied")||d.includes("EPERM")||243===s.status))throw new Error(`Failed to install ${r.displayName}: ${s}`);if(console.log("\n⚠️ "+n.t("install.permission_detected")+"\n"),"win32"===process.platform)try{const t=r.installCommand.replace("npm install -g","npm install -g --force");return console.log("🔧 "+n.t("install.trying_solution",{num:"1",desc:n.t("install.using_force")})),console.log(l.gray("$ ")+l.white(t)),o(t,{stdio:"inherit"}),void console.log("\n✅ "+n.t("install.permission_fixed"))}catch(o){i.warn("Retry install failed:",o),console.log("\n❌ "+n.t("install.auto_fix_failed")),console.log(l.yellow("\n📌 "+n.t("install.windows_solutions"))),console.log(""),console.log(l.cyan.bold(n.t("install.windows_solution_1_title"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step1"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step2"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step3"))),console.log(l.white(` ${r.installCommand}`)),console.log(""),console.log(l.cyan.bold(n.t("install.windows_solution_2_title"))),console.log(l.gray(" "+n.t("install.windows_solution_2_command"))),console.log(l.white(` ${r.installCommand.replace("npm install -g","npm install -g --prefix=%APPDATA%\\npm")}`)),console.log("");const{action:e}=await t.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===e)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(a))throw console.log(l.red("\n❌ "+n.t("install.still_not_installed",{tool:r.displayName}))),new Error(`${r.displayName} is not installed`);return void console.log(l.green("\n✅ "+n.t("install.verified_success",{tool:r.displayName})))}console.log(l.yellow("\n📌 "+n.t("install.unix_solutions"))),console.log(""),console.log(l.cyan.bold(n.t("install.unix_solution_1_title"))),console.log(l.gray(" "+n.t("install.unix_solution_1_desc"))),console.log(l.white(` sudo ${r.installCommand}`)),console.log("");const g="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally",m=e(g,g,{fallback:()=>g});console.log(l.cyan.bold(n.t("install.unix_solution_2_title"))),console.log(l.gray(" "+n.t("install.unix_solution_2_desc"))),console.log(l.blue(" 📖 "+n.t("install.npm_docs_link")+": ")+m),console.log("");const{action:p}=await t.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===p)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(a))throw console.log(l.red("\n❌ "+n.t("install.still_not_installed",{tool:r.displayName}))),new Error(`${r.displayName} is not installed`);console.log(l.green("\n✅ "+n.t("install.verified_success",{tool:r.displayName})))}}getToolConfig(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);try{return n.getConfig()}catch(n){return i.warn(`Failed to read config for ${o}:`,n),i.logError(`ToolManager.getToolConfig(${o})`,n),null}}updateToolConfig(o,n){const t=r(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(!t.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);t.updateConfig(n)}loadPrivateConfig(o,n,t,l){const e=r(o);if(!e)throw new Error(`Unknown tool: ${o}`);e.loadPrivateConfig({apiKey:n,baseUrl:a.getBaseUrl(),models:t,settings:a.getToolSettings(o),...l?{catalog:l}:{}})}async applyPrivateConfig(o,n,t){const l=r(o);if(!l)throw new Error(`Unknown tool: ${o}`);const e=l.wantsModelCatalog?await p(n):null;e?this.loadPrivateConfig(o,n,t,e):this.loadPrivateConfig(o,n,t)}applyNotes(o){const n=r(o);if(!n?.applyNotes)return[];try{return n.applyNotes()}catch(n){return i.logError(`ToolManager.applyNotes(${o})`,n),[]}}unloadPrivateConfig(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);n.unloadPrivateConfig()}clearPinnedModels(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);return a.setToolModel(o,null),n.clearPinnedModels?n.clearPinnedModels():[]}supportsClearPinnedModels(o){return Boolean(r(o)?.clearPinnedModels)}detectCurrentConfig(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);return n.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(n).map(o=>({file:o,backups:g(o)}))}restorePrivateConfig(o){const n=r(o);if(!n)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(n).map(o=>({file:o,result:m(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return c().filter(o=>!o.hidden).map(o=>u(o.name))}isGitInstalled(){try{const n="win32"===process.platform?"where git":"which git";return o(n,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
1
+ import{execSync as o}from"child_process";import{i18n as n}from"./i18n.js";import t from"inquirer";import l from"chalk";import e from"terminal-link";import s from"ora";import{logger as i}from"../utils/logger.js";import{configManager as r}from"./config.js";import{getAdapter as a,listAdapters as c,TOOL_ADAPTERS as d}from"./tools/registry.js";import{backupBeforeWrite as g,listBackups as m,restoreBackup as p}from"./tools/backup.js";import{existsSync as u,rmSync as f}from"fs";import{resolveModelCatalog as w}from"./model-catalog.js";function h(o){const n=d[o];return{name:n.name,command:n.command,installCommand:n.installCommand,configPath:n.configPath,displayName:n.displayName,...n.hidden?{hidden:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(d).map(o=>[o,h(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(n){const t=SUPPORTED_TOOLS[n];if(!t)return!1;const l=a(n);if(l?.isInstalled)try{return l.isInstalled()}catch{return!1}try{const n="win32"===process.platform?`where ${t.command}`:`which ${t.command}`;return o(n,{stdio:"pipe"}),!0}catch{return!1}}async installTool(r){const a=SUPPORTED_TOOLS[r];if(!a)throw new Error(`Unknown tool: ${r}`);const c=s(n.t("wizard.installing_tool")).start();try{c.info(l.gray("$ ")+l.white(a.installCommand)),c.stop(),o(a.installCommand,{stdio:"inherit"}),c.succeed(n.t("wizard.tool_installed"))}catch(s){c.fail(n.t("wizard.install_failed"));const d=(s.message||"")+(s.stderr?.toString()||"")+(s.stdout?.toString()||"");if(!(d.includes("EACCES")||d.includes("permission denied")||d.includes("EPERM")||243===s.status))throw new Error(`Failed to install ${a.displayName}: ${s}`);if(console.log("\n⚠️ "+n.t("install.permission_detected")+"\n"),"win32"===process.platform)try{const t=a.installCommand.replace("npm install -g","npm install -g --force");return console.log("🔧 "+n.t("install.trying_solution",{num:"1",desc:n.t("install.using_force")})),console.log(l.gray("$ ")+l.white(t)),o(t,{stdio:"inherit"}),void console.log("\n✅ "+n.t("install.permission_fixed"))}catch(o){i.warn("Retry install failed:",o),console.log("\n❌ "+n.t("install.auto_fix_failed")),console.log(l.yellow("\n📌 "+n.t("install.windows_solutions"))),console.log(""),console.log(l.cyan.bold(n.t("install.windows_solution_1_title"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step1"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step2"))),console.log(l.gray(" "+n.t("install.windows_solution_1_step3"))),console.log(l.white(` ${a.installCommand}`)),console.log(""),console.log(l.cyan.bold(n.t("install.windows_solution_2_title"))),console.log(l.gray(" "+n.t("install.windows_solution_2_command"))),console.log(l.white(` ${a.installCommand.replace("npm install -g","npm install -g --prefix=%APPDATA%\\npm")}`)),console.log("");const{action:e}=await t.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===e)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(r))throw console.log(l.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);return void console.log(l.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}console.log(l.yellow("\n📌 "+n.t("install.unix_solutions"))),console.log(""),console.log(l.cyan.bold(n.t("install.unix_solution_1_title"))),console.log(l.gray(" "+n.t("install.unix_solution_1_desc"))),console.log(l.white(` sudo ${a.installCommand}`)),console.log("");const g="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally",m=e(g,g,{fallback:()=>g});console.log(l.cyan.bold(n.t("install.unix_solution_2_title"))),console.log(l.gray(" "+n.t("install.unix_solution_2_desc"))),console.log(l.blue(" 📖 "+n.t("install.npm_docs_link")+": ")+m),console.log("");const{action:p}=await t.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===p)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(r))throw console.log(l.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(l.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}}getToolConfig(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);try{return n.getConfig()}catch(n){return i.warn(`Failed to read config for ${o}:`,n),i.logError(`ToolManager.getToolConfig(${o})`,n),null}}updateToolConfig(o,n){const t=a(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(!t.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);t.updateConfig(n)}forceResetConfig(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);const t=n.forceResetPaths?n.forceResetPaths():this.backupPathsFor(n),l=[];for(const o of t)u(o)&&(g(o),f(o,{force:!0}),l.push(o));return l}loadPrivateConfig(o,n,t,l,e={}){const s=a(o);if(!s)throw new Error(`Unknown tool: ${o}`);e.force&&this.forceResetConfig(o),s.loadPrivateConfig({apiKey:n,baseUrl:r.getBaseUrl(),models:t,settings:r.getToolSettings(o),...l?{catalog:l}:{}})}async applyPrivateConfig(o,n,t,l={}){const e=a(o);if(!e)throw new Error(`Unknown tool: ${o}`);const s=e.wantsModelCatalog?await w(n):null;l.force?this.loadPrivateConfig(o,n,t,s??void 0,{force:!0}):s?this.loadPrivateConfig(o,n,t,s):this.loadPrivateConfig(o,n,t)}applyNotes(o){const n=a(o);if(!n?.applyNotes)return[];try{return n.applyNotes()}catch(n){return i.logError(`ToolManager.applyNotes(${o})`,n),[]}}unloadPrivateConfig(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);n.unloadPrivateConfig()}clearPinnedModels(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);return r.setToolModel(o,null),n.clearPinnedModels?n.clearPinnedModels():[]}supportsClearPinnedModels(o){return Boolean(a(o)?.clearPinnedModels)}detectCurrentConfig(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);return n.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(n).map(o=>({file:o,backups:m(o)}))}restorePrivateConfig(o){const n=a(o);if(!n)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(n).map(o=>({file:o,result:p(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return c().filter(o=>!o.hidden).map(o=>h(o.name))}isGitInstalled(){try{const n="win32"===process.platform?"where git":"which git";return o(n,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
@@ -1 +1 @@
1
- import{join as e}from"path";import{homedir as o}from"os";import{claudeCodeManager as t}from"../claude-code-manager.js";import{backupBeforeWrite as a}from"./backup.js";const n=e(o(),".claude","settings.json"),i=e(o(),".claude.json");export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:"npm install -g @anthropic-ai/claude-code",configPath:n,loadPrivateConfig(e){a(n),a(i),t.loadPrivateConfig(e.apiKey,e.models)},unloadPrivateConfig(){a(n),t.unloadPrivateConfig()},detectCurrentConfig:()=>t.detectCurrentConfig(),getConfig:()=>({settings:t.getSettings(),mcp:t.getMCPConfig()}),updateConfig(e){const o=e||{};o.settings&&t.saveSettings(o.settings),o.mcp&&t.saveMCPConfig(o.mcp)},clearPinnedModels:()=>(a(n),t.clearPinnedModels()),backupPaths:()=>[n,i]};
1
+ import{join as e}from"path";import{homedir as t}from"os";import{claudeCodeManager as o}from"../claude-code-manager.js";import{backupBeforeWrite as a}from"./backup.js";const n=e(t(),".claude","settings.json"),i=e(t(),".claude.json");export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:"npm install -g @anthropic-ai/claude-code",configPath:n,loadPrivateConfig(e){a(n),a(i),o.loadPrivateConfig(e.apiKey,e.models)},unloadPrivateConfig(){a(n),o.unloadPrivateConfig()},detectCurrentConfig:()=>o.detectCurrentConfig(),getConfig:()=>({settings:o.getSettings(),mcp:o.getMCPConfig()}),updateConfig(e){const t=e||{};t.settings&&o.saveSettings(t.settings),t.mcp&&o.saveMCPConfig(t.mcp)},clearPinnedModels:()=>(a(n),o.clearPinnedModels()),backupPaths:()=>[n,i],forceResetPaths:()=>[n]};
@@ -1,6 +1,13 @@
1
1
  import { type ToolAdapter } from './types.js';
2
2
  import type { VibecliModels } from '../config.js';
3
3
  import { type ModelCatalog } from '../model-catalog.js';
4
+ /**
5
+ * Tool setting (config.yaml `tool_settings['claude-desktop'].hide_official_login`).
6
+ * `true` (default, same as the console's Desktop Assistant page) writes
7
+ * `disableDeploymentModeChooser: true`, hiding the Claude.ai sign-in choice so
8
+ * the app is gateway-only; `false` leaves the chooser visible.
9
+ */
10
+ export declare const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING = "hide_official_login";
4
11
  /** One model as advertised to Claude Desktop's picker (`inferenceModels[]`). */
5
12
  export interface InferenceModel {
6
13
  name: string;
@@ -1 +1 @@
1
- import{chmodSync as e,existsSync as t,mkdirSync as o,readFileSync as n,rmSync as r}from"fs";import{dirname as s}from"path";import{join as a}from"path";import{randomUUID as i}from"crypto";import{execFileSync as l}from"child_process";import{userInfo as c}from"os";import{logger as d}from"../../utils/logger.js";import{i18n as p}from"../i18n.js";import{BRAND_NAME as u}from"../brand.js";import{backupBeforeWrite as f,atomicWriteFile as m}from"./backup.js";import{toolHome as g}from"./types.js";import{baseModelId as y,isClaudeModel as h}from"../model-catalog.js";const C=u,k=["Claude_pzs8sxrjxfjjc","AnthropicPBC.Claude_fnn82j28hfe8t"],b=/^[a-f0-9-]{36}$/;function D(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=g(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return k.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const A=()=>a(claudeDesktopUserDataDir(),"configLibrary"),w=()=>a(A(),"_meta.json"),M=e=>a(A(),`${e}.json`),_=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function E(e){if(!t(e))return null;const o=n(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return D(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function v(n,r){const a=s(n);t(a)||o(a,{recursive:!0,mode:448}),f(n),m(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){d.logError("claude-desktop.writeJson.chmod",e)}}function j(){const e=E(w());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>D(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function P(e){return e?.entries.find(e=>e.name===C&&b.test(e.id))}const S={opus:0,fable:1,sonnet:2,haiku:3};function L(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=L(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function O(e){return L(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>y(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let a;if(t&&t.models.some(h)){a=[...new Set(t.models.filter(h).map(y))];for(const e of t.oneMillion)r.add(e)}else{a=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=y(o);n&&(a.includes(n)||a.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const i=e=>S[O(e)??""]??9;a.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=i(e)-i(t);if(0!==n)return n;const r=L(e),s=L(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=O(e);t&&a.includes(e)&&!c.has(t)&&c.set(t,e)}return a.map(e=>{const t=O(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let I=null;function x(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!0,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!0}}const $="HKCU\\SOFTWARE\\Policies\\Claude",U="HKLM\\SOFTWARE\\Policies\\Claude",G="vibecli-claude-policy.reg",T=e=>l("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let K=T;export function setRegRunnerForTests(e){K=e??T}function N(){return"win32"===process.platform}function R(e){let t;try{t=K(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function F(){if(null===R($))return;const e=a(claudeDesktopUserDataDir(),G);try{t(s(e))||o(s(e),{recursive:!0,mode:448}),f(e),K(["export",$,e,"/y"])}catch(e){d.logError("claude-desktop.snapshotPolicy",e)}}const B=Object.keys(x({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}}));export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=c().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return R(U)?U:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return d.logError("claude-desktop.detectManagedConfig",e),null}}const H="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",z="https://claude.ai/download",J="darwin"===process.platform?`open ${z}`:"win32"===process.platform?`start ${z}`:`xdg-open ${z}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:H,installCommand:J,configPath:w(),isInstalled:function(){const e=g();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...k.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},wantsModelCatalog:!0,loadPrivateConfig(e){const t=j()??{appliedId:"",entries:[]};let o=P(t);o||(o={id:i(),name:C},t.entries.push(o));const n=x(e);I={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=E(M(o.id))??{};v(M(o.id),{...r,...n}),t.appliedId=o.id,v(w(),t);const s=E(_())??{};"3p"!==s.deploymentMode&&v(_(),{...s,deploymentMode:"3p"}),N()&&function(e){F();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];K(["add",$,"/v",t,"/t",e,"/d",n,"/f"])}}(n)},unloadPrivateConfig(){N()&&function(e){const t=R($);if(!t)return;F();let o=t.size;for(const n of e)t.has(n)&&(K(["delete",$,"/v",n,"/f"]),o-=1);o<=0&&K(["delete",$,"/f"])}(B);const e=j(),t=P(e);if(!e||!t)return;f(M(t.id)),r(M(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(f(w()),r(w(),{force:!0})):v(w(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},detectCurrentConfig(){try{if(N()){const e=R($)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=P(j());if(!e)return{apiKey:null};const t=E(M(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return d.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=j(),t=P(e);return{meta:e,applied:t?E(M(t.id)):null,desktop:E(_()),...N()?{policy:Object.fromEntries(R($)??[])}:{}}}catch(e){return d.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;N()&&R($)?.has("inferenceModels")&&(F(),K(["delete",$,"/v","inferenceModels","/f"]),e=!0);const t=P(j()),o=t?E(M(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;v(M(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(I){const t=I.models.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", ");e.push(p.t(`tools.claude_desktop.models_written_${I.source}`,{count:String(I.models.length),list:t,groups:I.groups.join(" / ")}))}e.push(p.t("tools.claude_desktop.restart_hint")),N()&&e.push(p.t("tools.claude_desktop.registry_written",{key:$}));const t=detectManagedConfig();return t&&e.push(p.t("tools.claude_desktop.managed_conflict",{path:t})),e},backupPaths(){const e=[w(),_()];N()&&e.push(a(claudeDesktopUserDataDir(),G));try{const t=P(j());t&&e.push(M(t.id))}catch{}return e}};
1
+ import{chmodSync as e,existsSync as t,mkdirSync as o,readFileSync as n,rmSync as r}from"fs";import{dirname as s}from"path";import{join as i}from"path";import{randomUUID as a}from"crypto";import{execFileSync as l}from"child_process";import{userInfo as c}from"os";import{logger as d}from"../../utils/logger.js";import{i18n as p}from"../i18n.js";import{BRAND_NAME as u}from"../brand.js";import{backupBeforeWrite as f,atomicWriteFile as m}from"./backup.js";import{toolHome as g}from"./types.js";import{baseModelId as y,isClaudeModel as h}from"../model-catalog.js";const C=u;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";const k=["Claude_pzs8sxrjxfjjc","AnthropicPBC.Claude_fnn82j28hfe8t"],_=/^[a-f0-9-]{36}$/;function b(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=g(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return i(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:i(o,"AppData","Local");return k.map(t=>i(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??i(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:i(o,".config");return i(e,"Claude-3p")}}}const D=()=>i(claudeDesktopUserDataDir(),"configLibrary"),A=()=>i(D(),"_meta.json"),w=e=>i(D(),`${e}.json`),M=()=>i(claudeDesktopUserDataDir(),"claude_desktop_config.json");function E(e){if(!t(e))return null;const o=n(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return b(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function v(n,r){const i=s(n);t(i)||o(i,{recursive:!0,mode:448}),f(n),m(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){d.logError("claude-desktop.writeJson.chmod",e)}}function I(){const e=E(A());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>b(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function P(e){return e?.entries.find(e=>e.name===C&&_.test(e.id))}const S={opus:0,fable:1,sonnet:2,haiku:3};function L(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=L(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function O(e){return L(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>y(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(h)){i=[...new Set(t.models.filter(h).map(y))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=y(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>S[O(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=L(e),s=L(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=O(e);t&&i.includes(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=O(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let j=null,x=null;function T(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!0}}const G="HKCU\\SOFTWARE\\Policies\\Claude",U="HKLM\\SOFTWARE\\Policies\\Claude",$="vibecli-claude-policy.reg",K=e=>l("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let N=K;export function setRegRunnerForTests(e){N=e??K}function R(){return"win32"===process.platform}function F(e){let t;try{t=N(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function H(){if(null===F(G))return;const e=i(claudeDesktopUserDataDir(),$);try{t(s(e))||o(s(e),{recursive:!0,mode:448}),f(e),N(["export",G,e,"/y"])}catch(e){d.logError("claude-desktop.snapshotPolicy",e)}}const B=Object.keys(T({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}}));export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=c().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return F(U)?U:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return d.logError("claude-desktop.detectManagedConfig",e),null}}const z="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",J="https://claude.ai/download",W="darwin"===process.platform?`open ${J}`:"win32"===process.platform?`start ${J}`:`xdg-open ${J}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:z,installCommand:W,configPath:A(),isInstalled:function(){const e=g();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",i(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||i(e,"AppData","Local");o=[i(t,"AnthropicClaude"),i(t,"Programs","Claude"),...k.map(e=>i(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",i(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),i(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},wantsModelCatalog:!0,loadPrivateConfig(e){const t=I()??{appliedId:"",entries:[]};let o=P(t);o||(o={id:a(),name:C},t.entries.push(o));const n=T(e);x=!0===n.disableDeploymentModeChooser,j={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=E(w(o.id))??{};v(w(o.id),{...r,...n}),t.appliedId=o.id,v(A(),t);const s=E(M())??{};"3p"!==s.deploymentMode&&v(M(),{...s,deploymentMode:"3p"}),R()&&function(e){H();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];N(["add",G,"/v",t,"/t",e,"/d",n,"/f"])}}(n)},unloadPrivateConfig(){R()&&function(e){const t=F(G);if(!t)return;H();let o=t.size;for(const n of e)t.has(n)&&(N(["delete",G,"/v",n,"/f"]),o-=1);o<=0&&N(["delete",G,"/f"])}(B);const e=I(),t=P(e);if(!e||!t)return;f(w(t.id)),r(w(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(f(A()),r(A(),{force:!0})):v(A(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},detectCurrentConfig(){try{if(R()){const e=F(G)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=P(I());if(!e)return{apiKey:null};const t=E(w(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return d.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=I(),t=P(e);return{meta:e,applied:t?E(w(t.id)):null,desktop:E(M()),...R()?{policy:Object.fromEntries(F(G)??[])}:{}}}catch(e){return d.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;R()&&F(G)?.has("inferenceModels")&&(H(),N(["delete",G,"/v","inferenceModels","/f"]),e=!0);const t=P(I()),o=t?E(w(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;v(w(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(j){const t=j.models.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", ");e.push(p.t(`tools.claude_desktop.models_written_${j.source}`,{count:String(j.models.length),list:t,groups:j.groups.join(" / ")}))}null!==x&&e.push(p.t(x?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")),e.push(p.t("tools.claude_desktop.restart_hint")),R()&&e.push(p.t("tools.claude_desktop.registry_written",{key:G}));const t=detectManagedConfig();return t&&e.push(p.t("tools.claude_desktop.managed_conflict",{path:t})),e},forceResetPaths(){const e=[A(),M()];try{const t=P(I());t&&e.push(w(t.id))}catch{}return e},backupPaths(){const e=[A(),M()];R()&&e.push(i(claudeDesktopUserDataDir(),$));try{const t=P(I());t&&e.push(w(t.id))}catch{}return e}};
@@ -83,6 +83,13 @@ export interface ToolAdapter {
83
83
  * Hermes .env, Claude Code .claude.json) override it.
84
84
  */
85
85
  backupPaths?(): string[];
86
+ /**
87
+ * Files `--force` wipes (after snapshotting) before re-applying, so a config
88
+ * the user broke by hand is replaced wholesale by the recommended one.
89
+ * Defaults to `backupPaths()`; override to keep files that hold unrelated
90
+ * user state (Claude Code's `.claude.json` carries onboarding + MCP servers).
91
+ */
92
+ forceResetPaths?(): string[];
86
93
  }
87
94
  /**
88
95
  * Pick the single "main" model for tools that only take one model id.
@@ -46,7 +46,14 @@ export declare class Wizard {
46
46
  * the user backed out.
47
47
  */
48
48
  configureToolModel(toolName: string): Promise<boolean>;
49
- loadConfig(toolName: string): Promise<void>;
49
+ /**
50
+ * 「重置为推荐配置」:先确认,再整份删掉工具原有配置文件(已快照)并用当前
51
+ * profile 重写——给把配置改坏的用户兜底;随后走和 loadConfig 一样的收尾。
52
+ */
53
+ forceConfig(toolName: string): Promise<void>;
54
+ loadConfig(toolName: string, options?: {
55
+ force?: boolean;
56
+ }): Promise<void>;
50
57
  /**
51
58
  * 只摘掉钉死的模型、保留 API Key 与用户自有配置(hooks / MCP / 插件),
52
59
  * 让工具回到自带默认模型。
@@ -1 +1 @@
1
- import e from"inquirer";import t from"chalk";import o from"ora";import{configManager as a,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{i18n as d,detectSystemLang as p}from"./i18n.js";import{createBorderLine as m,createContentLine as u}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as _}from"./tools/codex.js";import{readFileSync as f}from"fs";import{dirname as y,join as h}from"path";import{fileURLToPath as z}from"url";const v=y(z(import.meta.url)),x=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(x.bold("\n"+m("╔","╗","═",this.BOX_WIDTH))),console.log(x.bold(u(e,"║","║",this.BOX_WIDTH,"center"))),console.log(x.bold(m("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(d.t("wizard.hint_navigate")),t.gray(d.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const o=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(o)}printBanner(){const e=65,t=d.t("wizard.banner_subtitle"),o=u(t,"║","║",e,"center"),a=u("","║","║",e,"center"),i=u(`API Helper v${function(){try{return JSON.parse(f(h(v,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>u(t,"║","║",e,"center")),r=[m("╔","╗","═",e),a,...n,a,i,o,m("╚","╝","═",e)];console.log(x.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 o;if(e.length>0){const t=e.map(e=>e.command).join(" / ");o=d.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(o+=" "+d.t("wizard.goodbye_claude_hint"))}else o=d.t("wizard.goodbye_message");console.log(t.green("\n👋 "+o))}async runFirstTimeSetup(){const e="zh_CN"===p();e&&(a.setLang("zh_CN"),d.setLocale("zh_CN")),this.resetScreen(),console.log(x.bold("\n"+d.t("wizard.welcome"))),console.log(t.gray(d.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(d.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_language"));const o=d.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+d.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return a.setLang(i),void d.setLocale(i)}}buildPresetChoices(){const o=n(),a=o.filter(e=>e.recommended),i=o.filter(e=>!e.recommended),r=e=>({name:(d.t(e.name)!==e.name?d.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 a.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+d.t("wizard.recommended")+" ──"))),s.push(...a.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+d.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const o=a.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:d.t("wizard.custom_model_mode"),choices:[{name:d.t("wizard.custom_model_single"),value:"single"},{name:d.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:d.t("wizard.input_custom_model"),default:i.sonnet}]);a.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:d.t("wizard.model_haiku"),default:o.haiku},{type:"input",name:"sonnet",message:d.t("wizard.model_sonnet"),default:o.sonnet},{type:"input",name:"opus",message:d.t("wizard.model_opus"),default:o.opus},{type:"input",name:"reasoning",message:d.t("wizard.model_reasoning"),default:o.reasoning}]);a.setModels(t)}console.log(t.green("\n✓ "+d.t("wizard.models_saved")))}async configModels(o){const i=a.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(d.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+d.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:d.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(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return a.setModels(e),console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),void(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:d.t("wizard.load_config_now"),choices:[{name:d.t("wizard.load_config_yes"),value:!0},{name:d.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configApiKey(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+d.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+d.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:d.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=o(d.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return a.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+d.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+d.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+d.t("wizard.api_key_network_error")));const{action:o}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===o)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:a}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+d.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===a)this.printGoodbye(),process.exit(0);else if("back"===a)return;await this.configureTool(a,t)}}async configureTool(o,a=!1){const i=c[o];if(i){if(!l.isToolInstalled(o)){console.log(t.yellow("\n"+d.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:a}=await e.prompt([{type:"confirm",name:"install",message:d.t("wizard.install_tool_confirm"),default:!0}]);if(!a)return;try{await l.installTool(o)}catch{return void console.log(t.red(d.t("wizard.install_failed")))}}a?await this.configureToolModel(o)&&await this.loadConfig(o):await this.showToolMenu(o)}}async showToolMenu(t){for(;;){this.resetScreen();const o=c[t];if(!o)return;this.createBox(o.displayName+" "+d.t("wizard.menu_title"));const a=[{name:"📥 "+d.t("wizard.action_load_config",{tool:o.displayName}),value:"load"},{name:"📤 "+d.t("wizard.action_unload_config",{tool:o.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&a.push({name:"🧹 "+d.t("wizard.action_clear_model",{tool:o.displayName}),value:"clear-model"}),a.push({name:"↩️ "+d.t("wizard.action_restore_config",{tool:o.displayName}),value:"restore"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+d.t("wizard.select_action"),choices:a}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(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!!a.getApiKey()?.trim()||a.listToolApiKeys().some(e=>Boolean(a.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const a=e?.trim();if(!a)return console.log(t.red("\n"+d.t("wizard.api_key_required"))),console.log(t.yellow(d.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(a))return a;const i=o(d.t("wizard.validating_api_key")).start(),n=await g(a);if(n.valid)return this.validatedApiKeys.add(a),i.succeed(d.t("wizard.api_key_valid")),a;this.validatedApiKeys.delete(a);const r="invalid_api_key"===n.error?d.t("wizard.api_key_invalid"):d.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+d.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]),!1;const p="claude-code"===i,m=s(i),u=p||!m?d.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+d.t("wizard.config_models"));const g=[{name:"✅ "+d.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+d.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+d.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}],{choice:f}=await this.promptWithHints([{type:"list",name:"choice",message:d.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===f.type)return!1;if("default"===f.type)a.setToolModel(i,null);else if("preset"===f.type)a.setToolModel(i,r(f.preset));else if("custom"===f.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),o=(t||"").trim();a.setToolModel(i,o?this.singleModelOverride(o):null)}else if("fetch"===f.type){const n=o(d.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:d.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+d.t("wizard.fetch_models_failed")));const{model:o}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(o||"").trim()}a.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=a.getToolSetting(i,_),{enableOneMillionContext:o}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:d.t("wizard.codex_enable_1m_context"),default:!1!==t}]);a.setToolSetting(i,_,Boolean(o))}return console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),p&&console.log(t.gray("💡 "+d.t("wizard.claude_model_hint"))),!0}async loadConfig(i){const n=a.getModelsForTool(i),r=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!r)return void await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]);const s=o(d.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,r,n),s.succeed(d.t("wizard.config_loaded",{tool:c[i]?.displayName||i}));const o=c[i]?.command;o&&console.log(t.green("\n"+d.t("wizard.run_tool_hint",{command:o})));for(const e of l.applyNotes(i))console.log(t.yellow("💡 "+e));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(this.printGoodbye(),process.exit(0))}catch(o){s.fail(d.t("wizard.config_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async clearPinnedModels(o){const a=c[o]?.displayName||o,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_clear_model",{tool:a}),default:!1}]);if(i){try{const e=l.clearPinnedModels(o);0===e.length?console.log(t.yellow("\n"+d.t("config.clear_model_none",{tool:a}))):(console.log(t.green("\n✓ "+d.t("config.clear_model_done",{tool:a}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(d.t("config.clear_model_restart_hint",{tool:a}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async unloadConfig(a){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_unload_config",{tool:c[a]?.displayName||a}),default:!1}]);if(!i)return;const n=o(d.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(a),n.succeed(d.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(o){n.fail(d.t("wizard.config_unload_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async restoreConfig(a){const i=c[a]?.displayName||a,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=o(d.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(a).filter(e=>e.result.restored);0===e.length?r.warn(d.t("wizard.restore_no_backup")):(r.succeed(d.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(d.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const o=a.getApiKey()||"",i=o.length>4?"sk-****"+o.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(x("── "+d.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+d.t("wizard.settings")+" ──")),{name:"🔑 "+d.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🌐 "+d.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+d.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():"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 o from"ora";import{configManager as a,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{i18n as d,detectSystemLang as p}from"./i18n.js";import{createBorderLine as m,createContentLine as u}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as _}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"./tools/claude-desktop.js";import{readFileSync as y}from"fs";import{dirname as h,join as z}from"path";import{fileURLToPath as v}from"url";const k=h(v(import.meta.url)),x=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(x.bold("\n"+m("╔","╗","═",this.BOX_WIDTH))),console.log(x.bold(u(e,"║","║",this.BOX_WIDTH,"center"))),console.log(x.bold(m("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(d.t("wizard.hint_navigate")),t.gray(d.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const o=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(o)}printBanner(){const e=65,t=d.t("wizard.banner_subtitle"),o=u(t,"║","║",e,"center"),a=u("","║","║",e,"center"),i=u(`API Helper v${function(){try{return JSON.parse(y(z(k,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>u(t,"║","║",e,"center")),r=[m("╔","╗","═",e),a,...n,a,i,o,m("╚","╝","═",e)];console.log(x.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 o;if(e.length>0){const t=e.map(e=>e.command).join(" / ");o=d.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(o+=" "+d.t("wizard.goodbye_claude_hint"))}else o=d.t("wizard.goodbye_message");console.log(t.green("\n👋 "+o))}async runFirstTimeSetup(){const e="zh_CN"===p();e&&(a.setLang("zh_CN"),d.setLocale("zh_CN")),this.resetScreen(),console.log(x.bold("\n"+d.t("wizard.welcome"))),console.log(t.gray(d.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(d.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_language"));const o=d.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+d.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return a.setLang(i),void d.setLocale(i)}}buildPresetChoices(){const o=n(),a=o.filter(e=>e.recommended),i=o.filter(e=>!e.recommended),r=e=>({name:(d.t(e.name)!==e.name?d.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 a.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+d.t("wizard.recommended")+" ──"))),s.push(...a.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+d.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const o=a.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:d.t("wizard.custom_model_mode"),choices:[{name:d.t("wizard.custom_model_single"),value:"single"},{name:d.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:d.t("wizard.input_custom_model"),default:i.sonnet}]);a.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:d.t("wizard.model_haiku"),default:o.haiku},{type:"input",name:"sonnet",message:d.t("wizard.model_sonnet"),default:o.sonnet},{type:"input",name:"opus",message:d.t("wizard.model_opus"),default:o.opus},{type:"input",name:"reasoning",message:d.t("wizard.model_reasoning"),default:o.reasoning}]);a.setModels(t)}console.log(t.green("\n✓ "+d.t("wizard.models_saved")))}async configModels(o){const i=a.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(d.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+d.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:d.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(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return a.setModels(e),console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),void(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:d.t("wizard.load_config_now"),choices:[{name:d.t("wizard.load_config_yes"),value:!0},{name:d.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configApiKey(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+d.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+d.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:d.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=o(d.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return a.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+d.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+d.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+d.t("wizard.api_key_network_error")));const{action:o}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===o)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:a}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+d.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===a)this.printGoodbye(),process.exit(0);else if("back"===a)return;await this.configureTool(a,t)}}async configureTool(o,a=!1){const i=c[o];if(i){if(!l.isToolInstalled(o)){console.log(t.yellow("\n"+d.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:a}=await e.prompt([{type:"confirm",name:"install",message:d.t("wizard.install_tool_confirm"),default:!0}]);if(!a)return;try{await l.installTool(o)}catch{return void console.log(t.red(d.t("wizard.install_failed")))}}a?await this.configureToolModel(o)&&await this.loadConfig(o):await this.showToolMenu(o)}}async showToolMenu(t){for(;;){this.resetScreen();const o=c[t];if(!o)return;this.createBox(o.displayName+" "+d.t("wizard.menu_title"));const a=[{name:"📥 "+d.t("wizard.action_load_config",{tool:o.displayName}),value:"load"},{name:"📤 "+d.t("wizard.action_unload_config",{tool:o.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&a.push({name:"🧹 "+d.t("wizard.action_clear_model",{tool:o.displayName}),value:"clear-model"}),a.push({name:"🧨 "+d.t("wizard.action_force_config",{tool:o.displayName}),value:"force"},{name:"↩️ "+d.t("wizard.action_restore_config",{tool:o.displayName}),value:"restore"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+d.t("wizard.select_action"),choices:a}]);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!!a.getApiKey()?.trim()||a.listToolApiKeys().some(e=>Boolean(a.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const a=e?.trim();if(!a)return console.log(t.red("\n"+d.t("wizard.api_key_required"))),console.log(t.yellow(d.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(a))return a;const i=o(d.t("wizard.validating_api_key")).start(),n=await g(a);if(n.valid)return this.validatedApiKeys.add(a),i.succeed(d.t("wizard.api_key_valid")),a;this.validatedApiKeys.delete(a);const r="invalid_api_key"===n.error?d.t("wizard.api_key_invalid"):d.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+d.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]),!1;const p="claude-code"===i,m=s(i),u=p||!m?d.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+d.t("wizard.config_models"));const g=[{name:"✅ "+d.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+d.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+d.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}],{choice:y}=await this.promptWithHints([{type:"list",name:"choice",message:d.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===y.type)return!1;if("default"===y.type)a.setToolModel(i,null);else if("preset"===y.type)a.setToolModel(i,r(y.preset));else if("custom"===y.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),o=(t||"").trim();a.setToolModel(i,o?this.singleModelOverride(o):null)}else if("fetch"===y.type){const n=o(d.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:d.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+d.t("wizard.fetch_models_failed")));const{model:o}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(o||"").trim()}a.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=a.getToolSetting(i,_),{enableOneMillionContext:o}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:d.t("wizard.codex_enable_1m_context"),default:!1!==t}]);a.setToolSetting(i,_,Boolean(o))}if("claude-desktop"===i){const t=a.getToolSetting(i,f),{hideOfficialLogin:o}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:d.t("wizard.desktop_hide_official_login"),default:!1!==t}]);a.setToolSetting(i,f,Boolean(o))}return console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),p&&console.log(t.gray("💡 "+d.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const o=c[t]?.displayName||t,{confirm:a}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("config.confirm_force",{tool:o}),default:!1}]);a&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=a.getModelsForTool(i),s=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]);const p=o(d.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),p.succeed(d.t("wizard.config_loaded",{tool:c[i]?.displayName||i})),n.force&&console.log(t.yellow(d.t("config.force_done",{tool:c[i]?.displayName||i})));const o=c[i]?.command;o&&console.log(t.green("\n"+d.t("wizard.run_tool_hint",{command:o})));for(const e of l.applyNotes(i))console.log(t.yellow("💡 "+e));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(this.printGoodbye(),process.exit(0))}catch(o){p.fail(d.t("wizard.config_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async clearPinnedModels(o){const a=c[o]?.displayName||o,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_clear_model",{tool:a}),default:!1}]);if(i){try{const e=l.clearPinnedModels(o);0===e.length?console.log(t.yellow("\n"+d.t("config.clear_model_none",{tool:a}))):(console.log(t.green("\n✓ "+d.t("config.clear_model_done",{tool:a}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(d.t("config.clear_model_restart_hint",{tool:a}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async unloadConfig(a){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_unload_config",{tool:c[a]?.displayName||a}),default:!1}]);if(!i)return;const n=o(d.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(a),n.succeed(d.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(o){n.fail(d.t("wizard.config_unload_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async restoreConfig(a){const i=c[a]?.displayName||a,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=o(d.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(a).filter(e=>e.result.restored);0===e.length?r.warn(d.t("wizard.restore_no_backup")):(r.succeed(d.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(d.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const o=a.getApiKey()||"",i=o.length>4?"sk-****"+o.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(x("── "+d.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+d.t("wizard.settings")+" ──")),{name:"🔑 "+d.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🌐 "+d.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+d.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():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
@@ -172,7 +172,9 @@
172
172
  "update_failed": "Update failed",
173
173
  "custom_model_mode": "Select custom model mode",
174
174
  "custom_model_single": "Single model for all roles",
175
- "custom_model_per_role": "Configure each role separately"
175
+ "custom_model_per_role": "Configure each role separately",
176
+ "desktop_hide_official_login": "Hide the official Claude.ai sign-in entry in Claude Desktop (gateway only)?",
177
+ "action_force_config": "Reset to recommended - (delete {{tool}}'s config files and rewrite them; repairs a broken config)"
176
178
  },
177
179
  "doctor": {
178
180
  "checking": "Running health check...",
@@ -268,7 +270,9 @@
268
270
  "clear_model_done": "Cleared the pinned model settings for {{tool}}; it now uses its built-in default:",
269
271
  "clear_model_none": "{{tool}} has no pinned model settings — nothing to clear",
270
272
  "clear_model_unsupported": "{{tool}} does not support clearing model settings",
271
- "clear_model_restart_hint": "Restart {{tool}} to apply (your API key, hooks and MCP config were left untouched)"
273
+ "clear_model_restart_hint": "Restart {{tool}} to apply (your API key, hooks and MCP config were left untouched)",
274
+ "confirm_force": "Reset {{tool}}? Its config files are snapshotted, deleted, and rewritten from the recommended configuration (fields you added by hand are lost; undo with restore)",
275
+ "force_done": "Reset {{tool}}'s config files (originals snapshotted; undo with `vibecli config {{tool}} restore`)"
272
276
  },
273
277
  "logs": {
274
278
  "directory": "Logs directory: {{dir}}",
@@ -313,7 +317,7 @@
313
317
  "non_interactive_aborted": "Aborted - missing required input"
314
318
  },
315
319
  "setup": {
316
- "usage": "Usage: vibecli setup --key sk-xxx or vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d or vibecli setup --1m|--no-1m",
320
+ "usage": "Usage: vibecli setup --key sk-xxx or vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d or vibecli setup --1m|--no-1m or vibecli setup --claude-official on|off",
317
321
  "codex_1m_enabled": "Codex 1M context is enabled",
318
322
  "codex_1m_disabled": "Codex 1M context is disabled",
319
323
  "codex_1m_missing_key": "No saved Codex API key was found; configure one with --key or --codexkey first",
@@ -331,7 +335,9 @@
331
335
  "apply_failed": "Failed to write {{tool}} config: {{reason}}",
332
336
  "install_hint": " Hint: {{tool}} not detected yet; install via {{install}}",
333
337
  "done": "Done: {{count}} tool(s) configured. Type {{commands}} in your terminal to start coding!",
334
- "skip_desktop_not_installed": "Claude Desktop is not installed; skipped (after installing, run vibecli setup --desktopkey sk-xxx or use the wizard)"
338
+ "skip_desktop_not_installed": "Claude Desktop is not installed; skipped (after installing, run vibecli setup --desktopkey sk-xxx or use the wizard)",
339
+ "desktop_official_login_missing_key": "No saved Claude Desktop API key found; run --key or --desktopkey first",
340
+ "claude_official_invalid": "Invalid value for --claude-official: {{value}} (expected on or off)"
335
341
  },
336
342
  "tools": {
337
343
  "claude_desktop": {
@@ -340,7 +346,9 @@
340
346
  "registry_written": "Also written to the registry policy {{key}} as a backstop (same as the downloadable .reg); the in-app \"Configure Third-Party Inference\" window will show as managed, and unloading removes it too",
341
347
  "models_written_gateway": "Wrote {{count}} models (1M flags from the gateway group table, matched groups: {{groups}}): {{list}}",
342
348
  "models_written_fallback": "Wrote {{count}} models (gateway group table unavailable or no group matched; 1M flags from built-in rules): {{list}}",
343
- "models_written_slots": "Wrote {{count}} models (offline: from the profile's model slots, gateway model list not fetched): {{list}}"
349
+ "models_written_slots": "Wrote {{count}} models (offline: from the profile's model slots, gateway model list not fetched): {{list}}",
350
+ "official_login_hidden": "The official Claude.ai sign-in entry is hidden; the desktop is gateway-only. Run vibecli setup --claude-official on to bring it back",
351
+ "official_login_shown": "The official Claude.ai sign-in entry stays visible, so users can switch between the gateway and their own account. Run vibecli setup --claude-official off to hide it"
344
352
  }
345
353
  }
346
354
  }
@@ -172,7 +172,9 @@
172
172
  "update_failed": "更新失败",
173
173
  "custom_model_mode": "选择自定义模型模式",
174
174
  "custom_model_single": "所有角色使用同一模型",
175
- "custom_model_per_role": "分别配置每个角色"
175
+ "custom_model_per_role": "分别配置每个角色",
176
+ "desktop_hide_official_login": "隐藏 Claude Desktop 里的官方登录(Claude.ai 账号)入口,只走网关?",
177
+ "action_force_config": "重置为推荐配置 - (删掉 {{tool}} 原配置文件后整份重写,修复改坏的配置)"
176
178
  },
177
179
  "doctor": {
178
180
  "checking": "正在进行健康检查...",
@@ -268,7 +270,9 @@
268
270
  "clear_model_done": "已清除 {{tool}} 钉死的模型设置,恢复使用工具自带默认模型:",
269
271
  "clear_model_none": "{{tool}} 当前没有钉死的模型设置,无需清理",
270
272
  "clear_model_unsupported": "{{tool}} 不支持清除模型设置",
271
- "clear_model_restart_hint": "请重启 {{tool}} 后生效(API Key 与你的 hooks / MCP 配置未改动)"
273
+ "clear_model_restart_hint": "请重启 {{tool}} 后生效(API Key 与你的 hooks / MCP 配置未改动)",
274
+ "confirm_force": "确认重置 {{tool}} 的配置吗?会先快照、再删掉它的配置文件,用推荐配置整份重写(您自行添加的字段会丢失,可用 restore 撤销)",
275
+ "force_done": "已重置 {{tool}} 的配置文件(原文件已快照,`vibecli config {{tool}} restore` 可撤销)"
272
276
  },
273
277
  "logs": {
274
278
  "directory": "日志目录: {{dir}}",
@@ -313,7 +317,7 @@
313
317
  "non_interactive_aborted": "已中止 - 缺少必要输入"
314
318
  },
315
319
  "setup": {
316
- "usage": "用法: vibecli setup --key sk-xxx 或 vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d 或 vibecli setup --1m|--no-1m",
320
+ "usage": "用法: vibecli setup --key sk-xxx 或 vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d 或 vibecli setup --1m|--no-1m 或 vibecli setup --claude-official on|off",
317
321
  "codex_1m_enabled": "Codex 1M 上下文已开启",
318
322
  "codex_1m_disabled": "Codex 1M 上下文已关闭",
319
323
  "codex_1m_missing_key": "未找到已保存的 Codex API Key;请先用 --key 或 --codexkey 完成配置",
@@ -331,7 +335,9 @@
331
335
  "apply_failed": "{{tool}} 配置写入失败: {{reason}}",
332
336
  "install_hint": " 提示: 尚未检测到 {{tool}},可运行 {{install}} 安装",
333
337
  "done": "完成: 已配置 {{count}} 个工具。终端输入 {{commands}} 即可开始编码!",
334
- "skip_desktop_not_installed": "未检测到已安装的 Claude Desktop,已跳过(装好后运行 vibecli setup --desktopkey sk-xxx 或在向导里配置)"
338
+ "skip_desktop_not_installed": "未检测到已安装的 Claude Desktop,已跳过(装好后运行 vibecli setup --desktopkey sk-xxx 或在向导里配置)",
339
+ "desktop_official_login_missing_key": "未找到已保存的 Claude Desktop API Key;请先用 --key 或 --desktopkey 完成配置",
340
+ "claude_official_invalid": "--claude-official 的值无效: {{value}}(只接受 on / off)"
335
341
  },
336
342
  "tools": {
337
343
  "claude_desktop": {
@@ -340,7 +346,9 @@
340
346
  "registry_written": "已同步写入注册表 {{key}} 作为兜底(与官网下载的 .reg 等效);应用内「Configure Third-Party Inference」窗口会显示为托管状态,移除配置时会一并清理",
341
347
  "models_written_gateway": "已写入 {{count}} 个模型(1M 标记依据网关分组表,匹配分组:{{groups}}):{{list}}",
342
348
  "models_written_fallback": "已写入 {{count}} 个模型(网关分组表不可用或未匹配到分组,1M 标记按内置规则):{{list}}",
343
- "models_written_slots": "已写入 {{count}} 个模型(离线:按当前 profile 的模型槽位,未拉取网关模型列表):{{list}}"
349
+ "models_written_slots": "已写入 {{count}} 个模型(离线:按当前 profile 的模型槽位,未拉取网关模型列表):{{list}}",
350
+ "official_login_hidden": "官方登录(Claude.ai 账号)入口已隐藏,桌面端只走网关;要恢复运行 vibecli setup --claude-official on",
351
+ "official_login_shown": "官方登录(Claude.ai 账号)入口保持可见,用户可在网关与官方账号间切换;要隐藏运行 vibecli setup --claude-official off"
344
352
  }
345
353
  }
346
354
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.45",
3
+ "version": "0.0.46",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",